【问题标题】:mysql order by with union doesn't seem to workmysql order by with union 似乎不起作用
【发布时间】: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

【问题讨论】:

    标签: mysql select sql-order-by union


    【解决方案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 上的问题,因为它不需要我合并这两个查询,但我最终还是学到了一些新东西,希望对你有所帮助(:

    【讨论】:

      猜你喜欢
      • 2022-11-12
      • 2014-05-30
      • 1970-01-01
      • 2014-08-03
      • 1970-01-01
      • 2017-11-02
      • 1970-01-01
      • 2011-12-20
      • 2016-11-22
      相关资源
      最近更新 更多