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不起作用