执行 T-SQL UNION 语句时出错。有啥解释吗?

Posted

技术标签:

【中文标题】执行 T-SQL UNION 语句时出错。有啥解释吗?【英文标题】:Error on execution of T-SQL UNION statement. Any explanation?执行 T-SQL UNION 语句时出错。有什么解释吗? 【发布时间】:2019-10-25 04:11:33 【问题描述】:

在 SQL Server 中执行 T-SQL UNION 语句时,我收到以下错误:

消息 156,级别 15,状态 1,服务器 WIN-ILO9GLLB9J0,第 7 行 关键字“UNION”附近的语法不正确

我是一名练习 SQL 查询的学生。我必须从表格中找到字符数最多的城市名称和字符数最少的城市名称。如果有字符长度相同的城市,我必须按字母顺序打印第一个城市。我写了以下代码:

SELECT TOP 1 CITY, LEN(CITY) 
FROM STATION 
ORDER BY LEN(CITY), CITY

UNION

SELECT TOP 1 CITY, LEN(CITY) 
FROM STATION 
ORDER BY LEN(CITY) DESC, CITY

这两个查询本身就可以正常工作。

【问题讨论】:

我感觉在子查询中不允许使用 ORDER BY。根据 Tim 的回答使用 Row_number 也是我的建议 @Alex ORDER BY 在伴随 TOP 时允许在子查询中。该顺序用于确定 TOP 将返回哪些行。 【参考方案1】:

这是使您当前的***联合语法工作的一种方法,使用子查询:

SELECT CITY, CITY_LEN
FROM
(
    SELECT TOP 1 CITY, LEN(CITY) AS CITY_LEN FROM STATION ORDER BY LEN(CITY), CITY
    UNION
    SELECT TOP 1 CITY, LEN(CITY) FROM STATION ORDER BY LEN(CITY) DESC, CITY
) t;

不过,我们也可以在这里轻松使用ROW_NUMBER

WITH cte AS (
    SELECT CITY, LEN(CITY) AS LEN_CITY,
        ROW_NUMBER() OVER (ORDER BY LEN(CITY), CITY) rn1,
        ROW_NUMBER() OVER (ORDER BY LEN(CITY) DESC, CITY) rn2
    FROM STATION
)

SELECT CITY, LEN_CITY
FROM cte
WHERE 1 IN (rn1, rn2);

Demo

【讨论】:

我同意这个答案,但我认为如果将 where 子句表示为 where rn1=1 or rn2=1 可能会更清楚【参考方案2】:

这可能是解决问题的更清晰的方法:

select * 
from station 
where len(city) in (
  select max(len(city)) from station
  union
  select min(len(city)) from station
)
order by len(city), city

如果该查询使用 top,您可以在子查询中使用 order by,但您不能有以下模式:

select * from x order by a
union 
select * from y order by a

虽然你被允许:

select * from x
union 
select * from y 
order by a

在这种情况下,排序是在联合之后完成的,并对整个联合集进行排序,就好像它是这样的:

select * from (
  select * from x
  union 
  select * from y 
) z
order by a

没有从 x 中进行第一次选择,对其进行排序,从 y 中进行选择,对其进行排序,然后将两组排序结果合并在一起的概念,除非您专门使用括号将它们变成子查询(即使这样,也只有在他们使用 TOP 的情况下)根据其他一些答案。以“x union y”的形式表示,必须只有一个 order by 语句,在 sql 的末尾,并且应用于整个集合。 sql server 对“在语句中间不能有 order by”(oracle 不是)如此挑剔的一个原因是,不能保证从 [union] 操作出来的行的顺序,所以它没有在途中订购它们是没有意义的 - 这是浪费时间和资源。一般规则是“如果您希望您的行按特定顺序排列,它应该是您做的最后一件事”,因此任何中间的排序步骤都是浪费。您可能会争辩说应该允许这个用例,我会发现它是一个有效的论点 - 同样有效,例如“不应该允许没有 order by 的顶部”。如果您深入研究它/询问 ms 的 sql 团队,您可能会发现解析 sql 的工作已经够难了,他们停在“在语句中间没有顺序”而不添加另一个规则“除非它是***操作”

【讨论】:

请注意,其他一些数据库,例如 mysql,实际上 do 支持直接取两个 TOP/LIMIT 子查询(但不是 SQL Server)+1 的并集的语法。 【参考方案3】:

这应该可行:

SELECT * FROM (select TOP 1 ... here)  AS q1
UNION ALL
SELECT * FROM (select TOP 1 ... here) AS q2

很明显,这与 top 1 ... order by 和 UNION 有关。

【讨论】:

怎么解决不了?我很困惑,但我添加了更多细节......【参考方案4】:

windows 函数有一个很好的答案,但由于您是初学者,您可以使用子查询来联合,最初的错误是因为您在尝试联合时不能提及明确的 ORDER BY,但使用子查询可以克服这个。

SELECT * 
FROM
    (SELECT TOP 1 CITY, LEN(CITY) LEN 
     FROM STATION 
     ORDER BY LEN(CITY), CITY) a

UNION

SELECT * 
FROM
    (SELECT TOP 1 CITY, LEN(CITY) LEN 
     FROM STATION 
     ORDER BY LEN(CITY) DESC, CITY) a

【讨论】:

感谢您的回答。他们真的有帮助。但是,我想知道联合在上面的查询中不起作用的原因可能是什么? 联合声明将提供两个输出的无序组合,因此当您提到一个订单时,会出现要保留哪个订单的冲突。

以上是关于执行 T-SQL UNION 语句时出错。有啥解释吗?的主要内容,如果未能解决你的问题,请参考以下文章

sql 中union all有啥用法

T-SQL语句中使用select…………union 插入数据是为啥不能使用DEFAULT

执行sql语句时参数化,有啥好处

在 T-Sql 插入语句中使用 Row Constructor 语法有啥好处?

使用大量 UNION 执行视图时出错

MySQL执行计划