在 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
查询的每个查询中,添加一个字段,该字段将作为您为UNION
的ORDER 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不起作用