Han*_*non 16 sql-server syntax cte t-sql
我只是在看StackOverflow上的一篇文章,其中 Aaron Bertrand 建议使用 CTE 而不是数字表,这是执行手头任务的一种优雅方式。我的问题是,为什么 CTE 的第一行以分号开头?
;WITH n AS (SELECT TOP (10000) n FROM
(SELECT n = ROW_NUMBER() OVER
(ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
) AS x ORDER BY n
)
SELECT n FROM n ORDER BY n; -- look ma, no gaps!
Run Code Online (Sandbox Code Playgroud)
这是为了确保 WITH 语句不会被解析为以前的内容SELECT
或其他内容吗?我在 SQL Server 2005 BOL 中没有看到关于在 WITH 之前使用分号的内容。
Aar*_*and 30
我总是在此处或 StackOverflow 上发帖时这样做,因为因为WITH
- 由于关键字过载 - 上一个命令需要终止分号。如果我粘贴一个使用 CTE 的代码示例,不可避免地会有一些用户将它粘贴到他们现有的代码中,并且前面的语句不会有分号。所以代码中断了,我收到如下抱怨:
你的密码坏了!我收到此错误消息:
Incorrect syntax near 'WITH'
...
虽然我愿意相信人们总是用分号结束他们的陈述会变得更好,但我宁愿预先排除噪音并始终包含它。有些人不喜欢它,但是<shrug />
。您可以根据需要在有效语句之前或之后包含任意数量的分号。这是有效的:
;;;;SELECT 1;;;;;;;;;;;;SELECT 2;;;;;;;;SELECT 3;;;;;
Run Code Online (Sandbox Code Playgroud)
因此,在定义需要它的语句之前有一个额外的分号并没有什么害处。即使它不那么漂亮,这样做也更安全。
必须用奇怪的措辞才能理解这一点,但自 SQL Server 2008 以来,“不以分号结束有效语句”实际上已被弃用。因此,正如我在博客文章中所述,我链接到上面,即使在以下情况下它不需要绕过错误,它应该在任何有效的地方使用。你可以在这里看到这个(这个条目已经存在多个版本):
semicolon
)如果没有例外,当然不会是 SQL Server。尝试这个:
BEGIN TRY;
SELECT 1/1;
END TRY;
BEGIN CATCH;
SELECT 1/1;
END CATCH;
Run Code Online (Sandbox Code Playgroud)
这不是规则的唯一例外,但它是我认为最不直观的例外。
为什么 CTE 应以分号开头?
不应该。之前的语句应该正确终止。
从文档中WITH common_table_expression
:
- 当在属于批处理的语句中使用 CTE 时,其前面的语句后面必须跟有分号。
如果您出于某种原因决定使用额外的语句终止符,我建议将终止符放在单独的行上,并用注释解释为什么它在那里:
; -- Previous statement must be properly terminated
WITH n AS (SELECT TOP (10000) n FROM
(SELECT n = ROW_NUMBER() OVER
(ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
) AS x ORDER BY n
)
SELECT n FROM n ORDER BY n;
Run Code Online (Sandbox Code Playgroud)
这可以避免误导人们认为它是公用表表达式语法的一部分,但事实并非如此。