【问题标题】:MYSQL: Join two sorted result setsMYSQL:加入两个排序的结果集
【发布时间】:2013-11-08 23:03:43
【问题描述】:

我正在建立一个网站,用户可以在其中免费创建帖子。他们还可以为他们的帖子支付一些额外的知名度,这意味着付费帖子将首先显示在搜索结果中。付费帖子和未付费帖子都在同一张表中,帖子是否付费是根据paid_until 列计算的,该列仅包含一个时间戳。

现在,为了简化分页,我希望能够从 MySQL 中获得一个不错的结果集,而无需通过 PHP 进行额外的排序,最好使用一个查询。结果集的总限制为 20(如每页 20 个帖子),它应该首先包含所有付费帖子(最多 20 个),然后添加 20-n 个未付费帖子。两个子集都应按其内部的列modified 进行排序。我需要稍后通过设置OFFSET 来跳过相同的结果。

我尝试了JOINUNIONGROUP BY 的不同变体,但还没有找到能够产生我想要的结果的解决方案。

有没有办法写这个:

(SELECT * FROM tbl_post WHERE paid_until >= :time_stamp ORDER BY modified DESC)
UNION
(SELECT * FROM tbl_post WHERE paid_until < :time_stamp ORDER BY modified DESC)

这样它才能真正起作用,因为UNION 搞乱了排序?

【问题讨论】:

  • 你不能按paid_until对所有帖子进行排序吗?只有 20 个付费帖子可能很难,但是如果超过 20 人为此付费怎么办?

标签: php mysql sql sorting select


【解决方案1】:

您可以对 UNION 查询的结果进行排序:

(SELECT * FROM tbl_post WHERE paid_until >= :time_stamp)
UNION
(SELECT * FROM tbl_post WHERE paid_until < :time_stamp)
ORDER BY paid_until >= :time_stamp DESC, modified DESC

在最后一个子查询周围保留括号很重要,因此 ORDER BY 显然在子查询之外。否则 SQL 将 ORDER BY 单独应用于子查询,然后在执行 UNION 的过程中再次取消排序。

子查询不需要排序,在最后一步就可以了。

但是这个查询可以进一步简化:

SELECT * FROM tbl_post
ORDER BY paid_until >= :time_stamp DESC, modified DESC
LIMIT :pagesize OFFSET :page_times_pagesize

【讨论】:

  • 我曾尝试在 ORDER BY 中使用表达式,但之前无法使其正常工作。我想我一定是在某种程度上弄错了语法,因为您的示例运行良好。谢谢!
【解决方案2】:

类似:

SELECT col1, col2, col3
FROM (    SELECT *,1 AS SortCol FROM tbl_post WHERE paid_until >= :time_stamp
          UNION
          SELECT *,2 AS SortCol FROM tbl_post WHERE paid_until < :time_stamp
      )AS sub
ORDER BY SortCol, modified DESC

【讨论】:

  • 完全符合我的需要,但 Bill Karwin 的回答这次接受了更简洁的解决方案。尽管我从您的回答中了解了使用 SortCols。谢谢!
  • 是的,我真的没想过我会像他那样回答,当您不是从同一个表中选择东西时,或者当您必须排序时,添加排序列更有用在不同的领域。
猜你喜欢
  • 2013-11-23
  • 1970-01-01
  • 2017-07-01
  • 2011-02-13
  • 1970-01-01
  • 1970-01-01
  • 2013-04-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多