在 mysql 中使用 union 和 order by 子句

Posted

技术标签:

【中文标题】在 mysql 中使用 union 和 order by 子句【英文标题】:Using union and order by clause in mysql 【发布时间】:2011-04-01 16:03:08 【问题描述】:

我想在 mysql 查询中使用 order by 和 union。 我正在根据不同标准从基于距离的表中获取不同类型的记录,以便在我的网站上进行搜索。 第一个选择查询返回与确切地点搜索相关的数据。 第二个选择查询返回与搜索地点 5 公里内的距离相关的数据。 第 3 次选择查询返回与搜索地点 5-15 公里内的距离相关的数据。

然后我使用联合合并所有结果并显示在带有分页的页面上。在适当的标题下,如'确切的搜索结果''5 公里内的结果'

现在我想根据 id 或 add_date 对结果进行排序。但是当我在查询末尾添加 order by 子句时(query1 union query 2 union query 3 order by add_date)。它对所有结果进行排序。但我想要的是它应该在每个标题下排序。

【问题讨论】:

您希望在每个表中排序的字段是什么类型? 【参考方案1】:

我正在尝试 (联合后排序) 进行以下查询,但不能:

select table1.*,table2.* 
from table1 
left join table2 on table2.id=0 
   union
select table1.*,table2.* 
from table2 
left join table1 on table2.i=table1.id
order by table1.id;

无论您的查询是什么,只需在所有选择联合查询中的列中添加同名别名 在上面的例子中,它将是:

select table1.id as md,table1.*,table2.* 
from table1 
left join table2 on table2.id=0 
   union
select table1.id as md,table1.*,table2.* 
from table2 
left join table1 on table2.i=table1.id
order by md;

【讨论】:

【参考方案2】:

只使用按列号排序(不要使用列名)。 每个查询都会返回一些列,因此您可以使用它的编号按任何所需的列进行排序。

【讨论】:

【参考方案3】:

当您在与UNION 结合使用的子查询中使用ORDER BY 子句时,mysql 将优化掉ORDER BY 子句。

这是因为默认情况下 UNION 返回一个无序列表,因此 ORDER BY 不会执行任何操作。

提到了优化in the docs并说:

要将 ORDER BY 或 LIMIT 应用于单个 SELECT,请放置子句 在括住 SELECT 的括号内:

(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10) UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);

但是,对单个 SELECT 语句使用 ORDER BY 意味着 与行在最终结果中出现的顺序无关 因为默认情况下 UNION 会产生一组无序的行。所以, 在这种情况下使用 ORDER BY 通常与 LIMIT,以便用于确定所选行的子集 检索 SELECT,即使它不一定会影响 这些行在最终 UNION 结果中的顺序。如果出现 ORDER BY 在 SELECT 中没有 LIMIT,它会被优化掉,因为它会有 反正没有效果。

这句话的最后一句话有点误导,因为它应该有效果。当您需要在子查询中排序时,这种优化会导致问题。

要强制 MySQL 不做这个优化,你可以像这样添加一个 LIMIT 子句:

(SELECT 1 AS rank, id, add_date FROM my_table WHERE distance < 5 ORDER BY add_date LIMIT 9999999999)
UNION ALL
(SELECT 2 AS rank, id, add_date FROM my_table WHERE distance BETWEEN 5 AND 15 ORDER BY rank LIMIT 9999999999)
UNION ALL
(SELECT 3 AS rank, id, add_date from my_table WHERE distance BETWEEN 5 and 15 ORDER BY id LIMIT 9999999999)

较高的LIMIT 表示如果您想做分页等操作,可以在整个查询中添加OFFSET

这还为您提供了额外的好处,即能够为每个联合 ORDER BY 不同的列。

【讨论】:

【参考方案4】:

不要忘记,union all 是一种无需排序或合并即可将记录添加到记录集中的方法(与 union 不同)。

例如:

select * from (
    select col1, col2
    from table a
    <....>
    order by col3
    limit by 200
) a
union all
select * from (
    select cola, colb
    from table b
    <....>
    order by colb
    limit by 300
) b

它使单个查询更清晰,并允许您按每个查询中的不同参数进行排序。但是,通过使用所选答案的方式,它可能会变得更加清晰,具体取决于复杂性和数据的相关程度,因为您正在概念化排序。它还允许您将人工列返回到查询程序,以便它具有可以排序或组织的上下文。

但是这种方式的优点是速度快,不会引入额外的变量,并且可以很容易地分离出包括排序在内的每个查询。添加限制的能力只是额外的奖励。

当然,您可以随意将联合全部转换为联合,并为整个查询添加排序。或者添加一个人工 id,这样可以很容易地在每个查询中按不同的参数进行排序,但其他方面与接受的答案相同。

【讨论】:

【参考方案5】:

您可以通过为每个选择添加一个名为 rank 的伪列来做到这一点,您可以先排序,然后再按其他条件排序,例如:

select *
from (
    select 1 as Rank, id, add_date from Table 
    union all
    select 2 as Rank, id, add_date from Table where distance < 5
    union all
    select 3 as Rank, id, add_date from Table where distance between 5 and 15
) a
order by rank, id, add_date desc

【讨论】:

为什么会有a和结尾? MySQL 要求派生表有别名。 @RedFilter,我不太明白。当我们可以简单地选择所有 3 个表然后执行order by 时,“全选作为派生表”的全部意义是什么? ("to sort or limit the entire UNION result, parenthesize the individual SELECT statements and place the ORDER BY or LIMIT after the last one")。将您的代码与i.stack.imgur.com/LpTMU.png 进行比较 @Pacerier 如果该语法适用于 MySQL,那就去吧!我的语法有点跨平台,我一般不使用 MySQL。不过,我实际上更喜欢它,因为它适用于更普遍的情况,例如,考虑何时只需要来自最后一个 UNION 查询的前十个匹配项 - 我认为无论如何你都必须回退到我的语法。 @Pacerier,还考虑到这种方式的值允许顶部的“select *”改为“select id,add_date”,如果你不想要,从结果中删除“rank”看看他们。【参考方案6】:

我尝试在联合之前将 order by 添加到每个查询中,例如

(select * from table where distance=0 order by add_date) 
union 
(select * from table where distance>0 and distance<=5 order by add_date)

但它似乎没有工作。它实际上并没有在每个选择的行内进行排序。

我认为您需要将 order by 保留在外部,并将 where 子句中的列添加到 order by,例如

(select * from table where distance=0) 
union 
(select * from table where distance>0 and distance<=5) 
order by distance, add_date

这可能有点棘手,因为您想按范围分组,但我认为它应该是可行的。

【讨论】:

user151841 union_sort 下面的想法将是处理分组的好方法 这不是 op 想要的【参考方案7】:

我在 join plus union 上得到了这个工作。

(SELECT 
   table1.column1,
   table1.column2,
   foo1.column4
 FROM table1, table2, foo1, table5
 WHERE table5.somerecord = table1.column1
 ORDER BY table1.column1 ASC, table1.column2 DESC
)

UNION

(SELECT
    ... Another complex query as above
)

ORDER BY column1 DESC, column2 ASC

【讨论】:

【参考方案8】:
(select add_date,col2 from table_name) 
  union 
(select add_date,col2 from table_name) 
  union 
(select add_date,col2 from table_name) 

order by add_date

【讨论】:

这行得通,但奇怪的是我需要改变一件事:我需要为排序的字段提供一个共享别名。除此之外,谢谢!【参考方案9】:

联合查询只能有一个主 ORDER BY 子句 IIRC。为此,在构成更大UNION 查询的每个查询中,添加一个字段,该字段将作为您为UNIONORDER BY 排序的一个字段。

例如,你可能有类似的东西

SELECT field1, field2, '1' AS union_sort
UNION SELECT field1, field2, '2' AS union_sort
UNION SELECT field1, field2, '3' AS union_sort
ORDER BY union_sort

union_sort 字段可以是您想要排序的任何内容。在这个例子中,它只是碰巧把第一个表的结果放在第一位,第二个表放在第二位,等等。

【讨论】:

【参考方案10】:

您可以使用子查询来执行此操作:

select * from (select values1 from table1 order by orderby1) as a
union all
select * from (select values2 from table2 order by orderby2) as b

【讨论】:

Tnx,很好的分开订单。如果 order 子句很常见,但我们希望将结果分开(而不是分开订单),我们也可以有不同的安排:SELECT * FROM ( SELECT aaa AS Col, 1 AS Official FROM table1 UNION ALL SELECT bbb AS Col, 0 AS Official FROM table2 ) AS tbl ORDER BY Official, Col 这是incorrect:ORDER BY 用于单个SELECT 语句并不意味着行在最终结果中出现的顺序 你是对的,接受的答案也是正确的。当我测试它时,这恰好运行良好。 shmosel(和 rickythefox)- union all 不会删除重复项,因此没有理由更改您的个人排序选择的类型。这就是为什么它在过去对你有用,也是为什么它会在未来对你有用。最终结果中的顺序混乱是由于 UNION (DISTINCT) 需要某种排序来有效地组合行。或者更具体地说,排序是因为它有效地组合了行。所以你可以依靠 union all 来保存你的子查询。 这对旧的 MySQL 版本非常有效,现在这种方法将工作。因为 SQL 标准不保证保留子查询的顺序。【参考方案11】:

这是因为您正在对整个结果集进行排序,您应该分别对联合的每个部分进行排序,或者您可以使用 ORDER BY (Something ie. subquery distance) THEN (something ie. row id) 子句

【讨论】:

【参考方案12】:

试试:

SELECT result.* 
FROM (
 [QUERY 1]
 UNION
 [QUERY 2]
) result
ORDER BY result.id

其中 [QUERY 1] 和 [QUERY 2] 是您要合并的两个查询。

【讨论】:

以上是关于在 mysql 中使用 union 和 order by 子句的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 HSQLDB 和 MySQL 之间的差异来处理 union/order?

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

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

MySQL中Union子句不支持order by的解决方法

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

UNION 和 ORDER BY 的使用不正确?