什么时候应该在SQL Server中使用分号?


221

在检查Web上的某些代码和SQL Server Management Studio生成的脚本时,我注意到某些语句以分号结尾。

那么我什么时候应该使用它呢?


23
SQL Server 2008 R2 msdn.microsoft.com/zh-cn/library/ms177563.aspx “ Transact-SQL语法约定(Transact-SQL)” == Transact-SQL语句终止符。尽管在此版本的SQL Server中,大多数语句不需要分号,但在将来的版本中将需要分号。
gerryLowry 2010年

2
尽管他们声称在将来的版本中将需要使用分号,但这永远不会实现。由于兼容性原因,他们永远不能要求这样做。它将破坏大约100%的应用程序。
usr

1
现在是2019年,最新版本的SQL Server仍然没有快乐地接受分号。就像@usr所说的那样,除非Microsoft想要进行100%的彻底中断,否则他们无法强制执行此操作。
伊恩·肯普

Answers:


151

从Ken Powers 的SQLServerCentral.Com 文章中

分号

分号字符是语句终止符。它是ANSI SQL-92标准的一部分,但从未在Transact-SQL中使用。确实,多年来编写T-SQL而不用遇到分号是可能的。

用法

在两种情况下,您必须使用分号。第一种情况是您使用通用表表达式(CTE),而CTE不是批处理中的第一条语句。第二个是您发布Service Broker语句的位置,而Service Broker语句不是批处理中的第一个语句。


9
THROW服务经纪人声明吗?在此示例中,我们需要在投掷之前添加分号:BEGIN ;THROW @Error, 'Invalid FundingID', 2; RETURN END
Chris Walsh

1
似乎他们基本上是在鼓励一般使用分号,方法是在最近几年引入的所有新语句类型之前都要求使用分号。(MERGE例如)。正如其他答案中提到的那样,在ANSI标准中它们是必需的
Mark Sowul

2
@maurocam我认为您没有正确阅读文档。如果您查看该链接,它将显示“ 以分号结束Transact-SQL语句”。不推荐使用。
卡托

如我所见,这并没有真正解决何时应该(而不是必须)使用分号的问题。
斯图尔特

81

默认情况下,SQL语句以分号终止。除非您(很少)设置了新的语句终止符,否则请使用分号终止语句。

如果只发送一条语句,从技术上讲,您可以省去语句终止符;在脚本中,由于要发送多个语句,因此需要它。

实际上,即使您只向数据库发送一条语句,也要始终包含终止符。

编辑:响应那些说法,[特定的RDBMS]不需要语句终止符,尽管这可能是正确的,但ANSI SQL标准却要求它们。在所有编程中,如果我们可以遵守标准而又不损失功能,则应该这样做,因为那样一来,我们的代码或习惯就不会与一个专有供应商绑定。

对于某些C编译器,即使Standard要求main返回int,也可能具有main return void。但是这样做会使我们的代码以及我们自己的可移植性降低。

有效编程的最大困难是不学习新事物,这是在学习不良习惯。在某种程度上,我们首先可以避免养成不良习惯,这对我们,我们的代码以及任何阅读或使用我们的代码的人都是胜利。



25

必须使用它。

使用分号终止语句的做法是标准做法,实际上是其他几种数据库平台的要求。SQL Server仅在特定情况下才需要分号,但是在不需要分号的情况下,使用分号不会引起问题。我强烈建议您采用以分号终止所有语句的做法。这样做不仅可以提高代码的可读性,而且在某些情况下可以节省一些麻烦。(当需要分号并且未指定时,SQL Server产生的错误消息并不总是很清楚。)

最重要的是:

SQL Server文档指示不使用分号终止T-SQL语句是不推荐使用的功能。这意味着长期目标是在产品的未来版本中强制使用分号。这是养成终止所有语句的习惯的另一个原因,即使当前不需要它也是如此。

来源: Itzik Ben-Gan提供的Microsoft SQL Server 2012 T-SQL基础


;以下两个查询(从本篇文章复制而来)为什么总是必须使用的一个示例:

BEGIN TRY
    BEGIN TRAN
    SELECT 1/0 AS CauseAnException
    COMMIT
END TRY
BEGIN CATCH
    SELECT ERROR_MESSAGE()
    THROW
END CATCH

在此处输入图片说明

BEGIN TRY
    BEGIN TRAN
    SELECT 1/0 AS CauseAnException;
    COMMIT
END TRY
BEGIN CATCH
    SELECT ERROR_MESSAGE();
    THROW
END CATCH

在此处输入图片说明


7
这似乎是一个很强的论点,您应该使用分号(由引号支持),但仅在必须的情况下使用。
Gregor Thomas

3
@Gregor,如果宣布必须使用分号并且not using them不建议使用分号,则应使用分号。如果不是这样,将来就有遭受痛苦的风险。如果您不打算升级/切换作业,并且始终要使用SQL Server 2000,那么您很安全:-)
gotqn 2015年

5
是的,我应该同意。但是他回答的第一行强调必须,但事实并非如此-至少现在还没有。
格雷戈尔·托马斯

2
带分号的示例Incorrect syntax near 'THROW'.在SQL Server 2008(10.0.6241.0)上运行,这是我在工作中必须处理的版本。它的工作原理如2012年所示。由于过时,我被说服开始使用分号。我不认为大多数时候在2008年会出现问题。
Pilot_51,2018年

1
您的答案是迄今为止最好的!它值得更多的赞扬。
斯图尔特


11

个人观点:仅在需要时使用它们。(有关所需列表,请参见上面的TheTXI的答案。)

由于编译器不需要它们,因此您可以将它们全部放置,但是为什么呢?编译器不会告诉您忘记了什么,因此最终会导致用法不一致。

[此意见特定于SQL Server。其他数据库可能有更严格的要求。如果您要编写要在多个数据库上运行的SQL,则您的要求可能会有所不同。]

上面的tpdi说:“在脚本中,由于要发送多个语句,因此需要它。” 这实际上是不正确的。您不需要它们。

PRINT 'Semicolons are optional'
PRINT 'Semicolons are optional'
PRINT 'Semicolons are optional';
PRINT 'Semicolons are optional';

输出:

Semicolons are optional
Semicolons are optional
Semicolons are optional
Semicolons are optional

1
您对此讨论有何看法? sqlservercentral.com/Forums/Topic636549-8-1.aspx(如果您没有帐户,可以使用bugmenot@bugmenot.com:bugmenot)
Anwar Pinto

2
我很高兴您清楚地表示这只是您的意见,但是我认为这不是一个很好的答案,因为它与Microsoft文档和ANSI标准都存在冲突。我认为发表评论会更好。(不试图打击您,您完全有权使用分号!)
打扰 izzy

4

关于T-SQL,我还有很多要学习的知识,但是在为事务编写一些代码(并将代码基于stackoverflow和其他站点的示例)时,我发现一种情况,似乎需要使用分号,并且如果缺少分号,该语句似乎根本不执行,并且不会引发任何错误。以上任何答案似乎都没有涵盖这一点。(这是使用MS SQL Server2012。)

一旦事务以我想要的方式工作,我决定围绕它进行尝试捕获,以便在出现任何错误时将其回滚。仅在执行完此操作后,交易才被提交(SSMS在尝试关闭窗口时通过一条漂亮的消息确认了这一点,该消息提醒您存在未提交的交易。

所以这

COMMIT TRANSACTION 

在BEGIN TRY / END TRY块外部可以很好地提交事务,但是在块内部必须

COMMIT TRANSACTION;

请注意,在尝试关闭查询选项卡之前,没有提供错误或警告,也没有指示事务仍未提交的指示。

幸运的是,这引起了一个巨大的问题,以至于显而易见的是存在一个问题。遗憾的是,由于未报告任何错误(语法或其他错误),因此,问题出在哪儿并不能立即发现。

相反,ROLLBACK TRANSACTION在带有或不带有分号的BEGIN CATCH块中似乎同样有效。

这样做可能有逻辑,但感觉像是爱丽丝梦游仙境。


一个可能的原因是COMMIT TRANSACTION接受一个可选的事务/保存点名称(它将忽略)。如果没有终止分号,COMMIT TRANSACTION则如果将下一个符号解析为标识符,则可以使用下一个符号,这可以从根本上改变代码的语义。如果这随后导致错误,则CATCH可能在COMMIT没有执行的情况下触发。相反,尽管ROLLBACK TRANSACTION也接受这样的可选标识符,但解析该错误最有可能导致交易无论如何被回滚。
Jeroen Mostert

3

看来,分号不应该结合使用游标操作:OPENFETCHCLOSEDEALLOCATE。我只是浪费了几个小时。我仔细查看了BOL,发现这些游标语句的语法中没有显示[;]!

所以我有:

OPEN mycursor;

这给了我错误16916。

但:

OPEN mycursor

工作了。


2
我认为这是不正确的。BOL在语句语法中提到分号不是很一致,例如看一下SELECT。另外,我目睹了OPEN someCursor;工作正常,FETCH,CLOSE和DEALLOCATE相同...
Valentino Vranken 2012年

对我来说,这表明解析器存在错误。您正在/正在使用哪个版本的SQL Server?
斯图尔特


0

在其中包含其他语句的批处理中使用DISABLE或ENABLE TRIGGER语句时,该语句之前的语句必须以分号结尾。否则,您将收到语法错误。我用这根头发撕掉了头发...之后,我偶然发现了关于MS Connect的同一件事。它已关闭,无法修复。

这里


0

注意:这将回答书面问题,但不能回答所陈述的问题。在这里添加它,因为人们会在搜索它

WITH递归CTE语句之前也使用分号:

;WITH Numbers AS
(
    SELECT n = 1
    UNION ALL
    SELECT n + 1
    FROM Numbers
    WHERE n+1 <= 10
)
SELECT n
FROM Numbers

此查询将生成一个名为Numbers的CTE,该CTE由整数[1..10]组成。通过创建仅具有值1的表,然后递归直到达到10来完成此操作。


8
从技术上讲,不是“之前”,而是之后的任何东西。如果with是批处理中的第一条语句,则不需要分号。
Tor Haugen

在WITH之前未使用过。这只是终止前一条语句的分号。似乎有些人已决定将分号放在此处,因为这是需要使用分号的情况。为什么这些人认为这胜过总是用分号终止语句,我不知道。
斯图尔特

0

如果您希望在SQLServer中收到随机的命令超时错误,请在CommandText字符串的末尾省略分号。

我不知道是否在任何地方对此进行了记录或它是否是一个错误,但是确实发生了,并且我从痛苦的经验中学到了这一点。

我有使用SQLServer 2008进行验证和可复制的示例。

aka-> 实际上,即使您只是向数据库发送一条语句,也要始终包含终止符。


如果查询的超时仅基于末尾是否有分号,那几乎可以肯定是由于执行计划不同而导致的,因为这些执行计划是通过与确切的查询文本进行匹配来缓存的,包括语义无关的内容诸如空格,注释和终止分号之类的东西。但是,分号本身完全不会引起任何计时问题。
Jeroen Mostert

-2

分号并不总是在复合SELECT语句中起作用。

比较普通复合SELECT语句的这两个不同版本。

代码

DECLARE @Test varchar(35); 
SELECT @Test=
    (SELECT 
        (SELECT 
            (SELECT 'Semicolons do not always work fine.';););); 
SELECT @Test Test;

退货

Msg 102, Level 15, State 1, Line 5
Incorrect syntax near ';'.

但是,代码

DECLARE @Test varchar(35)
SELECT @Test=
    (SELECT 
        (SELECT 
            (SELECT 'Semicolons do not always work fine.'))) 
SELECT @Test Test

退货

Test
-----------------------------------
Semicolons do not always work fine.

(1 row(s) affected)

11
[一年后]:哇,我感到惊讶的是,没有人对此答案发表评论!当然,这是行不通的,分号是语句分隔符,因此带分号的代码是:1- SELECT @ Test =(SELECT(SELECT(SELECT(分号'分号并不总是能正常工作。';陈述2-);-这3-)都不是;-那一个4-)都不是; -分号都不应该在3括号之后
PhpLou

1
您仅使用分号来终止语句。子查询不是语句。语句是按顺序执行的事物。在您的示例中,有以下三个语句:1. DECLARE @ Test varchar(35)2. SELECT @ Test =(SELECT(SELECT(SELECT(分号“分号并不总是能正常工作。”)))))3. SELECT @ Test测试
Stewart
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.