带有 UNION 子句的 ORDER BY

Posted

技术标签:

【中文标题】带有 UNION 子句的 ORDER BY【英文标题】:ORDER BY with UNION clause 【发布时间】:2020-11-26 09:49:34 【问题描述】:

无论我在哪里搜索,我都发现下面的代码应该可以工作。

SELECT id, name, age FROM A
UNION
SELECT id, name, age FROM B
ORDER BY name

我的查询是在特定日期之间搜索数据库中的每个值,然后只选择该指定日期之前的几个值。这个查询本身是有效的,但我想按某个列对其进行排序,我得到了错误:

如果语句包含 UNION、INTERSECT 或 EXCEPT 运算符,则 ORDER BY 项必须出现在选择列表中

这是我的代码:

DECLARE @inidate DATE = '20201001', @findate DATE = '20201031'

SELECT bo.id, bo.date, bo.status
FROM BO (nolock)
JOIN BO2 (nolock) ON BO2.bo2stamp = BO.bostamp
WHERE (BO.date BETWEEN @inidate AND @findate)
  AND (BO.tabela1 IN ('INSTALED','CANCELED'))

UNION

SELECT bo.id, bo.date, bo.status
FROM BO (nolock)
JOIN BO2 (nolock) ON BO2.bo2stamp = BO.bostamp
WHERE (BO.date < @inidate)
  AND (BO.tabela1 NOT IN ('INSTALED','CANCELED'))
ORDER BY bo2.u_registration_date

我已经尝试了此处显示的代码,但在ORDER BY 上出现错误

预期的 AS、ID 或 QUOTED_ID

SELECT * 
FROM
    ([my query])
ORDER BY bo2.u_registration_date

我也试过

SELECT * 
FROM ([1st query])
UNION 
SELECT * 
FROM ([2nd query])
ORDER BY bo2.u_registration_date

【问题讨论】:

错误告诉你问题;当SELECT 不在时,您不能通过u_registration_date 订购。如果您必须具有该顺序的数据但未公开,则子查询中的UNION 查询带有列,然后将其排除在外部查询中,但对其进行排序。跨度> 您也真的需要针对每张桌子的NOLOCK 提示吗?您确实了解它的作用,对吗? NOLOCK 不是一个神奇的“更快”按钮,很容易导致您的结果不正确。 Bad habits : Putting NOLOCK everywhere 错误信息很清楚,你不能按 u_registration_date 订购,因为你没有选择那一列。 你可以用UNION ALL 代替吗?还是您想要/需要消除重复项? 有人告诉我使用nolock,因为如果我有一个很棒的数据库,我可能会以某种方式阻止这些表并且无法再访问它。我信任这个人,因为我对 SQL 的了解非常有限,大约 2 个月前我就开始学习了。 【参考方案1】:

您需要将union 放在子查询中,并在外部查询中排序。此外,子查询需要返回您要用于排序的列。

SELECT *
FROM (
    SELECT bo.id, bo.date, bo.status, bo2.u_registration_date
        FROM BO
        JOIN BO2 ON BO2.bo2stamp = BO.bostamp
        WHERE BO.date BETWEEN @inidate AND @findate AND BO.tabela1 IN ('INSTALED','CANCELED')
    UNION
        SELECT bo.id, bo.date, bo.status, bo2.u_registration_date
        FROM BO
        JOIN BO2 ON BO2.bo2stamp = BO.bostamp
        WHERE BO.date < @inidate AND BO.tabela1 NOT IN ('INSTALED','CANCELED')
) t
ORDER BY u_registration_date

请注意,在这里使用UNION 没有多大意义。这两个成员仅在日期过滤器上有所不同,因此在功能上您的查询等同于:

SELECT bo.id, bo.date, bo.status, bo2.u_registration_date
FROM BO
JOIN BO2 ON BO2.bo2stamp = BO.bostamp
WHERE BO.date < @findate AND BO.tabela1 NOT IN ('INSTALED','CANCELED')
ORDER BY bo2.u_registration_date

【讨论】:

...尽管您可以评论说,在某些情况下,联合版本可能运行得更快,具体取决于索引方案。但是无论哪种方式都可以为您的答案 +1。 如果我不使用UNION,我的查询不会在我首先选择的日期之间返回任何数据,它不会显示我在日期内的任何数据指定 UNION 不过滤数据,@pauLo_0liveira。它只是将 2+ 个具有相同定义的数据集组合在一起,并从 2+ 个数据集中返回 DISTINCT 行。如果UNION 查询返回行,那么至少一个内部查询也会返回。 我在括号后的选择和别名中都添加了bo2.u_registration_date,但现在我的错误是它没有找到bo2.u_registration_date,我尝试在select *之后添加它,但是让它识别我需要在括号前添加BO2 成功了,我是通过bo2.u_registration_date 订购的,而不仅仅是u_registration_date。非常感谢

以上是关于带有 UNION 子句的 ORDER BY的主要内容,如果未能解决你的问题,请参考以下文章

我可以在 SQL 中使用 UNION 子句的查询中添加 ORDER BY 子句吗?

如何在 UNION 之间的 SQL 中放置 ORDER BY 子句

在 sql 查询中使用 group/order by 和 union 子句

在 mysql 中使用 union 和 order by 子句

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

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