mysql order by with union 似乎不起作用

Posted

技术标签:

【中文标题】mysql order by with union 似乎不起作用【英文标题】:mysql order by with union doesn't seem to work 【发布时间】:2012-01-30 21:26:05 【问题描述】:

这是我的查询

(SELECT * FROM `jokes` WHERE `flags` < 5 AND (`title` LIKE "%only three doors%" OR `joke` LIKE "%only three doors%") ORDER BY `ups` DESC,`downs` ASC)
UNION
(SELECT * FROM `jokes` WHERE `flags` < 5 AND (`title` LIKE "%only%" OR `joke` LIKE "%only%") ORDER BY `ups` DESC,`downs` ASC)
UNION
(SELECT * FROM `jokes` WHERE `flags` < 5 AND (`title` LIKE "%three%" OR `joke` LIKE "%three%") ORDER BY `ups` DESC,`downs` ASC)
UNION
(SELECT * FROM `jokes` WHERE `flags` < 5 AND (`title` LIKE "%doors%" OR `joke` LIKE "%doors%") ORDER BY `ups` DESC,`downs` ASC)
 LIMIT 0, 30

由于某种原因,它似乎并没有按起起落落排序......它只是按照它们在数据库中的自然顺序将结果扔回给我。

当我将其缩减为仅一个查询时,它可以正常工作,但除此之外,它似乎忽略了它。

我也不想按整个结果排序,否则我会输入LIMIT 0,30 Order By blah

【问题讨论】:

【参考方案1】:

来自 mysql documentation:

...对单个 SELECT 语句使用 ORDER BY 意味着 与行在最终结果中出现的顺序无关 因为 UNION 默认会生成一组无序的行。

基本上,联合中的ORDER 唯一有用的情况是您同时使用LIMIT

所以如果你的查询是这样的:

(SELECT * FROM `jokes` WHERE `flags` < 5 AND (`title` LIKE "%only three doors%" OR `joke` LIKE "%only three doors%") ORDER BY `ups` DESC,`downs` ASC LIMIT 10)
UNION ...

然后您会看到根据该顺序返回的前十条记录,但它们不一定按顺序显示。

更新:

试试这个 -

(SELECT *, 1 as ob FROM `jokes` WHERE `flags` < 5 AND (`title` LIKE "%only three doors%" OR `joke` LIKE "%only three doors%") )
UNION
(SELECT *, 2 as ob FROM `jokes` WHERE `flags` < 5 AND (`title` LIKE "%only%" OR `joke` LIKE "%only%") )
UNION
(SELECT *, 3 as ob FROM `jokes` WHERE `flags` < 5 AND (`title` LIKE "%three%" OR `joke` LIKE "%three%") )
UNION
(SELECT *, 4 as ob FROM `jokes` WHERE `flags` < 5 AND (`title` LIKE "%doors%" OR `joke` LIKE "%doors%"))
 ORDER BY `ob`, `ups` DESC,`downs` ASC LIMIT 0, 30

【讨论】:

您对如何让它按照我想要的方式工作有什么想法吗?本质上,我想组合不同的查询,并让每个查询单独按起伏排序,然后一个接一个地组合。 所以第一个查询排序,然后第二个排序。如果第一个大于 30,那么它只会在第一个查询中显示前 30 个。 Bleh,这很难。你是说你不想对整个集合进行正确排序?只需将一个排序集附加到另一个排序集的末尾并取前 30 个? 没错。有分页,所以当有人转到下一页时,我会限制 30,60 等。 这很奇怪。为什么 MySQL 在连接时每个人都想随机排序一个有序列表?【参考方案2】:

我得到了解决方案:

SELECT *
FROM (
    (SELECT 1 as SortRank, uid, title, state, zip, region,cantone FROM company WHERE city=".$city." AND region=".$region." AND cantone=".$cantone.")
     UNION
    (SELECT 2 as SortRank, uid, title, state, zip, region,cantone FROM company WHERE region=".$region." AND cantone=".$cantone.")
    union all
    (SELECT 3 as SortRank, uid, title, state, zip, region,cantone FROM company WHERE cantone=".$cantone.")
) As u
GROUP BY uid 
ORDER BY SortRank,state=2, title ASC
LIMIT 0,10

在上面的查询中,我想要结果,例如。首先显示带有城市、地区和州的所有记录,然后如果城市不可用,则显示带有地区和州的所有记录,然后显示带有城市的州的所有记录。 因此,删除我使用 GROUP BY 子句的重复记录,它将根据查询组对所有记录进行排序,然后是 state=2 的所有记录。

【讨论】:

谢谢!我花了几个小时试图弄清楚这一点。 GROUP BY uid 不能保证返回特定的行。您依赖于未记录的行为,它返回它出现的第一个行为。也就是说,不能保证如果 uid 同时出现在 SortRank 1 和 SortRank 2 中,那么它在 group by 之后仍然会有 SortRank 1【参考方案3】:

查询的作用是将每个子查询单独排序并统一所有子查询。不能保证结果会被订购。

您需要做的是这样订购统一查询:

Select * from (
  (SELECT *, 1 as `p` FROM `jokes` WHERE `flags` < 5 AND (`title` LIKE "%only three doors%" OR `joke` LIKE "%only three doors%"))
  UNION
  (SELECT *, 2 as `p` FROM `jokes` WHERE `flags` < 5 AND (`title` LIKE "%only%" OR `joke` LIKE "%only%"))
  UNION
   (SELECT *, 3 as `p` FROM `jokes` WHERE `flags` < 5 AND (`title` LIKE "%three%" OR `joke` LIKE  "%three%"))
  UNION
  (SELECT *, 4 as `p` FROM `jokes` WHERE `flags` < 5 AND (`title` LIKE "%doors%" OR `joke` LIKE "%doors%"))
    ) ORDER BY `p` ASC, `ups` DESC,`downs` ASC

【讨论】:

我曾想过,但正如我上面提到的,这不是我要寻找的结果。第一个查询的所有结果都应始终位于第二个查询的任何结果之前。 我编辑了查询以满足您的需求(添加了一个额外的字段“p”) 我会把它给你,但另一个人首先有正确的解决方案。不过谢谢 这个查询的另一件事,在Select * FROM 中包围整个事情实际上没有返回任何结果【参考方案4】:

您应该能够使用 UNION ALL 来删除重复删除(以及完整的结果集排序)。使用该结果集应该按照查询中选择语句的顺序。

【讨论】:

所以只需将 UNION 替换为 UNION ALL? 试一试,看看是否有帮助,如果没有,我浪费了你不超过 20 秒的时间 :) ..(我没有方便的本地 mysql 来测试它,但它应该有所作为) 等等,我不想重复。 然后坚持添加额外的列进行排序,就像已经接受的答案一样。【参考方案5】:

也许这与问题有点无关,但对于那些想要合并两个或更多查询的人来说:不同的列:

由于两个查询中的列不相同,因此您无法使用一个 order by 语句,您可以考虑添加“假”列以使两个查询中的列数相等,这就是我的答案到 HackerRank 上的 excerise 与此处提出的问题类似

WITH sub AS 
(
(SELECT CONCAT(Name , "(" , SUBSTRING(OCCUPATION,1,1) , ")") as first , Name , OCCUPATION , -1 as counts FROM OCCUPATIONS)
UNION ALL
(SELECT CONCAT("There are a total of " , COUNT(OCCUPATION) , " " , LOWER(OCCUPATION) , "s" , ".") as first , "z" as Name , OCCUPATION , COUNT(OCCUPATION) as counts FROM OCCUPATIONS
GROUP BY OCCUPATION)
)

SELECT first FROM sub
ORDER BY Name ASC , counts ASC , OCCUPATION ASC

注意:您应该为假列选择适当的值,以使您的行位于正确的位置(注意我的查询中的-1 as counts FROM OCCUPATIONS"z" as Name

我最初误解了 HackerRank 上的问题,因为它不需要我合并这两个查询,但我最终还是学到了一些新东西,希望对你有所帮助(:

【讨论】:

以上是关于mysql order by with union 似乎不起作用的主要内容,如果未能解决你的问题,请参考以下文章

在 mysql 中使用 union 和 order by 子句

mysql union 语句与 order by

为啥在mysql中第一个union两个子句的order by不起作用

MySQL中union和order by一起使用的方法

在 MySQL 中使用 Union All 和 Order By

Mysql:使用union all时使用order by和limit到单独的查询