8

我要认输了。

前言:我想用任何 N 来做这个,但为了简单起见,我将 N 设置为 3。

我有一个查询(特别是 MySQL),它需要从表中提取数据并根据该表中的前 3 个值进行排序,然后回退到其他排序标准。

所以基本上我有这样的东西:

SELECT tbl.id 
FROM
  tbl1 AS maintable 
  LEFT JOIN 
  tbl2 AS othertable 
  ON
  maintable.id = othertable.id
ORDER BY 
  othertable.timestamp DESC, 
  maintable.timestamp DESC

这是所有基本的教科书内容。但问题是我需要第一个 ORDER BY 子句来仅获取 othertable.timestamp 中的三个最大值,然后回退到 maintable.timestamp。

此外,对 othertable 执行 LIMIT 3 子查询并加入它是不行的,因为这需要与应用于 maintable 的任意数量的 WHERE 条件一起工作。

我几乎能够使其与这样的基于用户变量的方法一起使用,但它失败了,因为它不考虑排序,所以它将采用它找到的前三个其他表值:

ORDER BY 
  (
    IF(othertable.timestamp IS NULL, 0, 
      IF(
        (@rank:=@rank+1) > 3, null, othertable.timestamp
      )
    )
  ) DESC

(语句前有一个@rank:=0)

所以...有什么建议吗?我对这个问题失去了理智。我为此拥有的另一个参数是,由于我只更改现有的(非常复杂的)查询,因此我无法进行包装外部查询。另外,如前所述,我使用的是 MySQL,因此不幸的是,任何使用 ROW_NUMBER 函数的解决方案都无法实现。

提前感谢大家。

编辑。这是一些示例数据,其中时间戳简化为更简单的整数,以说明我需要什么:

maintable

id      timestamp
1       100
2       200
3       300
4       400
5       500
6       600

othertable

id     timestamp
4      250
5      350
3      550
1      700

=>

1
3
5
6
4
2

如果出于某种原因我们将 WHERE NOT maintable.id = 5 添加到查询中,这就是我们应该得到的:

1
3
4
6
2

...因为现在 4 是 othertable 中引用此集合的前 3 个值之一。

如您所见,othertable 中 id 为 4 的行不包含在排序中,因为它是时间戳值降序排列的第四个,因此它会退回到按基本时间戳排序。

现实世界对此的需求是:我在“maintable”中有内容,而“othertable”基本上是具有“特色日期”时间戳的特色内容的标记。我有一个视图,我应该将最后 3 个特色项目浮动到顶部,而列表的其余部分只是一个按时间顺序排列的反向列表。

4

3 回答 3

1

修改后的答案:

select ilv.* from
(select sq.*, @i:=@i+1 rn from
 (select @i := 0) i
  CROSS JOIN 
 (select m.*, o.id o_id, o.timestamp o_t
  from maintable m
  left join othertable o
  on m.id = o.id
  where 1=1
  order by o.timestamp desc) sq
) ilv
order by case when o_t is not null and rn <=3 then rn else 4 end,
         timestamp desc

SQLFiddle在这里

修改where 1=1子查询内的条件sq以匹配所需的复杂选择条件,并limit在最终order by分页要求后添加适当的条件。

于 2013-07-29T19:25:37.467 回答
1

也许是这样的。

SELECT
  id
FROM
  (SELECT 
    tbl.id,
    CASE WHEN othertable.timestamp IS NULL THEN 
      0 
    ELSE 
      @i := @i + 1
    END AS num,
    othertable.timestamp as othertimestamp,
    maintable.timestamp as maintimestamp
  FROM
    tbl1 AS maintable
    CROSS JOIN (select @i := 0) i 
    LEFT JOIN tbl2 AS othertable 
      ON maintable.id = othertable.id
  ORDER BY
    othertable.timestamp DESC) t
ORDER BY
  CASE WHEN num > 0 AND num <= 3 THEN
    othertimestamp
  ELSE
    maintimestamp
  END DESC
于 2013-07-29T19:11:45.470 回答
1

您可以使用如下的联合查询吗?

(SELECT id,timestamp,1 AS isFeatured FROM tbl2 ORDER BY timestamp DESC LIMIT 3)
UNION ALL
(SELECT id,timestamp,2 AS isFeatured FROM tbl1 WHERE NOT id in (SELECT id from tbl2 ORDER BY timestamp DESC LIMIT 3))
ORDER BY isFeatured,timestamp DESC

这可能有点多余,但它在语义上更接近您所问的问题。这也将允许您参数化要返回的特色结果的数量。

于 2016-08-11T20:01:27.577 回答