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

Cai*_*ard 5 sql sql-server sql-server-2017

我已经阅读了我能找到的与此错误相关的所有问题,但它们并没有完全描述这种情况。在其他情况下,人们正在做一些事情,例如按顺序仅引用一个别名表(从联合的一侧) - 我理解为什么 SQLS 在我读过的所有其他问题中抱怨这个特定的错误。

我不明白为什么 SQL Server 对此有异议order by;order by 中提到的唯一列肯定是结果集 select 的成员:

--example data:
-- a,b,c
-- 1, ,2
--  ,3,5

SELECT    1 AS a, null AS b, 2 AS c INTO #tmp
UNION
SELECT null AS a,    3 AS b, 5 AS c 

--let's call it a lame version of a rollup
SELECT * FROM #tmp            --detail rows
UNION ALL
SELECT a, b, SUM(c) FROM #tmp --summary row
GROUP BY a, b

--the problem
ORDER BY COALESCE(a, b);

DROP TABLE #tmp;
Run Code Online (Sandbox Code Playgroud)

结果集包含列ab,我看不出有任何歧义。即使对所有内容(以不同方式)使用别名也无济于事:

SELECT t.a AS z, t.b AS y, t.c FROM #tmp t
UNION ALL
SELECT u.a AS z, u.b AS y, SUM(c) AS c FROM #tmp u
GROUP BY u.a, u.b
ORDER BY COALESCE(z, y);
Run Code Online (Sandbox Code Playgroud)

事实上,奇怪的是,SQL Server 似乎抱怨得更多:

Msg 207, Level 16, State 1, Line 6
Invalid column name 'z'.
Msg 207, Level 16, State 1, Line 6
Invalid column name 'z'.           --why complain twice?
Msg 207, Level 16, State 1, Line 6
Invalid column name 'y'.
Msg 104, Level 16, State 1, Line 6
ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.
Run Code Online (Sandbox Code Playgroud)

唯一有效的是将其包装为另一个选择:

SELECT * FROM(
  SELECT * FROM #tmp
  UNION ALL
  SELECT a, b, SUM(c) AS c FROM #tmp
  GROUP BY u.a, u.b
) a
ORDER BY COALESCE(a, b);

SELECT * FROM(
  SELECT t.a AS z, t.b AS y, t.c FROM #tmp t
  UNION ALL
  SELECT u.a AS z, u.b AS y, SUM(c) AS c FROM #tmp u
  GROUP BY u.a, u.b
) z
ORDER BY COALESCE(z, y);
Run Code Online (Sandbox Code Playgroud)

这就是我的想法,从概念上讲,SQL Server 在处理结果集之前正在处理它的结果集order by。那么,给出了什么?

Cai*_*ard 3

根据HoneyBadger的注释,似乎人们实际上必须只在错误消息的表面值上采用SQLS,而不是假设它从联合查询构建结果集,并使用前导选择中给定列的名称作为别名,然后进行排序..

这...

SELECT a, b, COALESCE(a,b) FROM t
UNION ALL
SELECT a, b, COALESCE(a,b) FROM u
ORDER BY COALESCE(a,b)
Run Code Online (Sandbox Code Playgroud)

COALESCE(a,b)...有效,大概是因为它直接在选择列表以及 ORDER BY 中指定

这...

SELECT * FROM(
  SELECT a, b FROM t
  UNION ALL
  SELECT a, b FROM u
)z
ORDER BY COALESCE(a,b)
Run Code Online (Sandbox Code Playgroud)

...有效,大概是因为正在排序的查询不包含 UNION

使用非工作形式的其他数据库的有趣结果组合:

甲骨文:

ORA-01785: ORDER BY 项必须是 SELECT 列表表达式的编号

邮政格雷斯:

错误:无效的 UNION/INTERSECT/EXCEPT ORDER BY 子句详细信息:只能使用结果列名称,不能使用表达式或函数。提示:将表达式/函数添加到每个 SELECT 中,或将 UNION 移至 FROM 子句中

MySQL:

(作品)