什么时候不应该使用分号?

2024-01-01

Or: 什么不是 T-SQL 语句?

除了解决歧义之外,T-SQL 语法不需要分号来终止语句。尽管如此,伊齐克·本-甘 http://www.sqlmag.com/blog/puzzled-by-t-sql-blog-15/tsql/semicolon-140706建议使用分号来终止 T-SQL 语句,因为它使代码更清晰、更易读、更易于维护且更可移植。

我不知道什么是有效的 T-SQL 语句的精确定义,所以我可能会感到困惑。但据我所知,BEGIN...END 块是一个 T-SQL 语句,因此应该以分号终止。例如:

IF OBJECT_ID('tempdb.dbo.#TempTable') IS NOT NULL
BEGIN
  DROP TABLE #TempTable;
END;

微软的代码示例开始...结束文档 http://msdn.microsoft.com/en-us/library/ms190487.aspx支持这个猜想:

USE AdventureWorks2008R2;
GO
BEGIN TRANSACTION;
GO
IF @@TRANCOUNT = 0
BEGIN
    SELECT FirstName, MiddleName 
    FROM Person.Person WHERE LastName = 'Adams';
    ROLLBACK TRANSACTION;
    PRINT N'Rolling back the transaction two times would cause an error.';
END;
ROLLBACK TRANSACTION;
PRINT N'Rolled back the transaction.';
GO
/*
Rolled back the tranaction.
*/

Itzik Ben-Gan 在练习 1-1 的代码示例中反驳了这一点T-SQL 基础知识 http://www.sql.co.il/books/tsqlfund2008/9780735626010_MSSQLServer08T-SQLFundamentals_ch03.pdf:

SET NOCOUNT ON;
USE TSQLFundamentals2008;
IF OBJECT_ID('dbo.Nums', 'U') IS NOT NULL DROP TABLE dbo.Nums;
CREATE TABLE dbo.Nums(n INT NOT NULL PRIMARY KEY);

DECLARE @i AS INT = 1;
BEGIN TRAN
  WHILE @i <= 100000
  BEGIN
    INSERT INTO dbo.Nums VALUES(@i);
    SET @i = @i + 1;
  END
COMMIT TRAN
SET NOCOUNT OFF;

微软的Transact-SQL 语法约定 http://msdn.microsoft.com/en-us/library/ms177563.aspx文档指出分号“在 T-SQL 的未来版本中将是必需的”。

在评论 Microsoft 打算在未来版本的 T-SQL 中使用分号时,Itzik 指出了一些不应终止的异常:

到目前为止,只要求在特定情况下使用分号。现在看起来计划是使其成为 SQL Server 未来版本中所有* T-SQL 语句的必需终止符。

(*) 当然,有些情况不应该以分号结束;这些包括(但不限于):

  • BEGIN

  • 开始传输

  • IF

  • ELSE

  • WHILE

  • 开始尝试

  • END TRY

  • 开始捕捉

Itzik 似乎与自己言行一致,但微软本身并没有遵循他的建议。比较微软的BEGIN TRANSACTION;和伊齐克的BEGIN TRAN在前面的例子中。

在我维护的代码中,我什至看到了BEGIN以分号结尾的关键字:

IF @HasWidget = 0x1
BEGIN;
  SELECT WidgetID
  FROM tbWidgets;
END;

我相信 T-SQL 解析器可能会考虑后面的分号BEGIN关键字终止一个空语句而不是终止BEGIN关键字本身;我不相信BEGIN本身是一个有效的 T-SQL 语句。

SQL Server 2008 成功解析并执行以下查询的事实支持了这一猜想:

SELECT 0;;

这很令人困惑,因为 T-SQL 语言没有广泛可用的规范,例如Java语言规范 http://java.sun.com/docs/books/jls/对于 Java,因此没有 T-SQL 语句的正式定义。

我错了吗? T-SQL 是否存在这样的规范,并且它是否公开可用?

否则,我应该相信Itzik所说的吗?


摘要,基于 OP 的原始引用列表。

是的分号:

  • 开始传输;

没有分号:

  • BEGIN
  • IF
  • ELSE
  • WHILE
  • 开始尝试
  • END TRY
  • 开始捕捉

另外,在之后使用它们END and END CATCH.

Details:

BEGIN TRAN是一个语句,应该以分号结束。

微软的文档指出了可选的分号:

BEGIN { TRAN | TRANSACTION } 
    [ { transaction_name | @tran_name_variable }
      [ WITH MARK [ 'description' ] ]
    ]
[ ; ]

微软的例子有分号:

BEGIN TRAN T1;
UPDATE table1 ...;
BEGIN TRAN M2 WITH MARK;
UPDATE table2 ...;
SELECT * from table1;
COMMIT TRAN M2;
UPDATE table3 ...;
COMMIT TRAN T1;

以上两篇均来自:

https://msdn.microsoft.com/en-us/library/ms188929(v=sql.90).aspx https://msdn.microsoft.com/en-us/library/ms188929(v=sql.90).aspx

它们与当前文档匹配:

https://msdn.microsoft.com/en-us/library/ms188929(v=sql.120).aspx https://msdn.microsoft.com/en-us/library/ms188929(v=sql.120).aspx

As for BEGIN...END,微软文档没有提供明确的指导。

该定义没有分号:

BEGIN
     { 
    sql_statement | statement_block 
     } 
END

然而,他们的示例在 END 之后显示了一个分号:

IF @@TRANCOUNT = 0
BEGIN
    SELECT FirstName, MiddleName 
    FROM Person.Person WHERE LastName = 'Adams';
    ROLLBACK TRANSACTION;
    PRINT N'Rolling back the transaction two times would cause an error.';
END;

https://msdn.microsoft.com/en-us/library/ms190487.aspx https://msdn.microsoft.com/en-us/library/ms190487.aspx

该尾随分号与 Microsoft 自己的文档不一致IF流语言构造的控制:

IF Boolean_expression 
     { sql_statement | statement_block } 
[ ELSE 
     { sql_statement | statement_block } ] 

该定义及其代码示例均未显示任何分号:

DECLARE @compareprice money, @cost money 
EXECUTE Production.uspGetList '%Bikes%', 700, 
    @compareprice OUT, 
    @cost OUTPUT
IF @cost <= @compareprice 
BEGIN
    PRINT 'These products can be purchased for less than 
    $'+RTRIM(CAST(@compareprice AS varchar(20)))+'.'
END
ELSE
    PRINT 'The prices for all products in this category exceed 
    $'+ RTRIM(CAST(@compareprice AS varchar(20)))+'.'

https://msdn.microsoft.com/en-us/library/ms182717(v=sql.110).aspx https://msdn.microsoft.com/en-us/library/ms182717(v=sql.110).aspx

然而,他们的ELSE文档虽然在定义中也没有显示任何分号,但在示例中的最后一个分号之后确实显示了一个分号END.

定义:

IF Boolean_expression { sql_statement | statement_block } 
    [ ELSE { sql_statement | statement_block } ] 

Example:

IF 1 = 1 PRINT 'Boolean_expression is true.'
ELSE PRINT 'Boolean_expression is false.' ;

https://msdn.microsoft.com/en-us/library/ms182587(v=sql.110).aspx https://msdn.microsoft.com/en-us/library/ms182587(v=sql.110).aspx

ANSI 标准无法解决歧义,因为这些是非标准扩展:

ANSI SQL 标准不涵盖控制流语句 因为这些是专有的 SQL 扩展。 SQL Server 书籍 网上关于这个主题和许多例子都是粗略的(截至此 写作)不一致并且并不总是包含声明 终结者。此外,控制流语句块是 由于许多变化、嵌套和可选的开始/结束而令人困惑 规格。

http://www.dbdelta.com/always-use-semicolon-statement-terminators/ http://www.dbdelta.com/always-use-semicolon-statement-terminators/

然而,服务器的行为揭示了一些线索。以下不是 SQL Server 2005 中的语法错误:

DECLARE @foo int;
IF @foo IS NULL
BEGIN
    WITH Blah AS
    (
        SELECT
            'a' AS a
    )
    SELECT
        a
    FROM        Blah;
END

So the BEGIN本身不需要分号。但是,以下内容在 SQL Server 2005 中确实会产生语法错误:

DECLARE @foo int;
IF @foo IS NULL
BEGIN
    WITH Blah AS
    (
        SELECT
            'a' AS a
    )
    SELECT
        a
    FROM        Blah;
END
WITH Blah2 AS
(
    SELECT
        'a' AS a
)
SELECT
    a
FROM        Blah2;

上述结果导致此错误:

消息 319,级别 15,状态 1,第 13 行关键字附近的语法不正确 '和'。如果该语句是公用表表达式或 xmlnamespaces 子句中,前面的语句必须以 分号。

它还会在 SQL Server 2008 R2 中引发该错误。

这变得更加令人困惑。微软的文档TRY...CATCH在后面显示一个可选的分号END CATCH,他们的例子与此一致。

BEGIN TRY
     { sql_statement | statement_block }
END TRY
BEGIN CATCH
     [ { sql_statement | statement_block } ]
END CATCH
[ ; ]

但是,如果您在接受治疗后立即出现 CTEBEGIN TRY,如果没有分号,就会抛出错误。

BEGIN TRY
    WITH Blah AS
    (
        SELECT
            'a' AS a
    )
    SELECT
        a
    FROM        Blah;
END TRY
BEGIN CATCH
END CATCH

在 SQL Server 2008 R2 中,上述批处理会引发此错误:

消息 319,级别 15,状态 1,第 2 行 关键字附近的语法不正确 '和'。如果该语句是公用表表达式,则 xmlnamespaces 子句或更改跟踪上下文子句,前面的 语句必须以分号结束。

该错误意味着BEGIN TRY是一个声明(它不是),并且分号“修复”了问题(它确实解决了)。没错,这有效:

BEGIN TRY;
    WITH Blah AS
    (
        SELECT
            'a' AS a
    )
    SELECT
        a
    FROM        Blah;
END TRY
BEGIN CATCH
END CATCH

然而,微软表示这不是一个好的做法:

Microsoft 发布于 12/29/2009 下午 12:11 我正在解决 将 SQL11 错误对应为“设计使然”。解释如下:

END TRY 和 BEGIN CATCH 之间不允许有分号, 因为它们实际上并不是不同的陈述,而是陈述的一部分 相同的 TRY-CATCH 语句。我们只允许在分隔时使用分号 一个序列中的两个语句。

解释一下为什么我们在 BEGIN TRY 和之后允许使用分号 开始捕捉。这些关键字充当开始的“括号” 嵌入的语句序列。 BEGIN TRY/BEGIN CATCH 之后的分号 被解析为嵌入序列的一部分,其中包含第一条语句 在空的序列中。虽然我们允许这种语法,但我不会 推荐它作为良好的编码实践,因为它会产生错误 BEGIN TRY/BEGIN CATCH 的印象是独立的、独立的 声明。

处理这种情况的推荐方法是使用额外的BEGIN...END为了清楚起见:

BEGIN TRY
    BEGIN
        WITH Blah AS
        (
            SELECT
                'a' AS a
        )
        SELECT
            a
        FROM        Blah;
    END
END TRY
BEGIN CATCH
END CATCH

然而,那END之前END TRY可能应该有一个分号。毕竟,这会引发错误:

BEGIN TRY
    BEGIN
        WITH Blah AS
        (
            SELECT
                'a' AS a
        )
        SELECT
            a
        FROM        Blah;
    END
    WITH Blah2 AS
    (
        SELECT
            'b' AS b
    )
    SELECT
        b
    FROM        Blah2;
END TRY
BEGIN CATCH
END CATCH

也许总是在 CTE 之前WITH分号并不那么愚蠢。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么时候不应该使用分号? 的相关文章

  • SQL Server 表不使用默认值

    我正在使用 SSIS 包填充表 这个想法是 每当包上传到表时 它都会使用时间戳记该值getdate 当我打开它时 我的 DDL 看起来像这样 CREATE TABLE REPORTING post ssis table 1 validati
  • TSQL - 如何在 BEGIN .. END 块内使用 GO?

    我正在生成一个脚本 用于自动将更改从多个开发数据库迁移到登台 生产 基本上 它需要一堆更改脚本 并将它们合并成一个脚本 将每个脚本包装在一个IF whatever BEGIN END陈述 然而 有些脚本需要GO语句 以便 SQL 解析器在创
  • 用数组“插入”

    我想知道是否有一种方法可以在值列表上使用 插入 我正在尝试这样做 insert into tblMyTable Col1 Col2 Col3 values value1 value2 value3 所以 我想说的是 value2 将是一个字
  • TSQL 帮助 - 一种获取行第 N 列中的值的方法?

    我希望找到一种方法来获取数据集第 N 列中的值 因此 对于 N 6 我想要 SELECT Column6Value from MyTable where MyTable RowID 14 有没有办法在 SQL Server 2005 中实现
  • 函数 SQL 中的函数

    我可以在表值函数中调用标量函数吗 Thanks 是的 只要表值函数完成后返回一个表即可 用户自定义函数可以嵌套 也就是说 一个用户定义的函数可以 呼叫另一个 嵌套级别为 被调用函数时递增 开始执行 并在以下时间递减 被调用函数完成 执行 用
  • 即使没有显式事务,SQL Server 也会获取锁吗?

    我第一次阅读有关 MSSQL 锁定的内容 在很多地方 锁定机制概念依赖于事务的存在 我想知道在不涉及任何事务的情况下是否可以锁定 一般来说 当不存在显式事务时 每个 SQL 语句都在自动 自动提交 事务中执行 在这种情况下将应用正常的锁定行
  • 如何在 T-SQL 中将 CSV 转换为记录集?

    在我的存储过程中 我传递一个过滤器 使用 WHERE Column IN 子句 作为参数 参数值以 CSV 形式给出 将此 CSV 转换为记录集的最佳方法是什么 例子 SELECT FROM Employee WHERE Name IN J
  • 拆分列中的字符串并在列中添加值

    我有一个包含几行数据的表 如下所示 16 W 2 Work ALBO 00 Proposal ALxO Amendement 1 20091022 signed pdf 17 W 2 Work ALBO 00 Proposal Level1
  • 选择具有 SQL Server XML 列类型的特定行

    我正在尝试从类似于以下定义的表中选择数据 Column Data Type Id Int DataType Int LoggedData XML 但我只想选择具有特定 DataType 值并且在 LoggedData 列中包含字符串 或评估
  • 如何搜索例程的内容/(SP-触发函数)

    我需要在数据库内所有例程的例程主体 存储过程 函数 触发器 中搜索文本 我该怎么做 Thanks SELECT OBJECT NAME object id FROM sys sql modules WHERE definition LIKE
  • 从 Getdate() 获取时间

    我想采取Getdate 结果 例如 2011 10 05 11 26 55 000 into 11 26 55 AM 我看过其他地方并发现 Select RIGHT CONVERT VARCHAR GETDATE 100 7 这给了我 11
  • sql server 如果不存在则插入并获取插入的id到另一个表中

    我是 SQL Server 新手 正在开发一个记录日志的项目 该表有一个 URL 列 varchar max 它具有重复值 我创建了另一个表 它仅存储不同的 URL ID 存储在主表中 这是我执行此操作的存储过程 CREATE TABLE
  • 如何在 SQL 中刷新 PRINT 缓冲区?

    我在 SQL Server 2005 中有一个运行时间非常长的存储过程 我正在尝试调试它 并且我使用 print 命令来执行它 问题是 我只是在存储过程的最后从 SQL Server 获取消息 我希望能够刷新消息缓冲区并在存储过程的运行时立
  • 使用左连接在单个更新语句中更新多个表

    我意识到我所要求的可能是不可能的 我想基于 LEFT JOIN 和 WHERE 子句对两个单独的表执行 UPDATE 这是我的尝试 UPDATE PERIODDATES as pd periods2 as p2 SET pd PERIODC
  • 如何根据条件选择列?

    我有一个名为 status 的变量 我在此 select 语句之前设置了它 Select ordr num as num ordr date as date ordr ship with as shipwith From order whe
  • SQL Server 之间的日期 LIKE

    请帮我如何插入LIKE 之间的日期 例子是 SELECT FROM table WHERE Date BETWEEN startDate AND endDate 所以在这段代码中我应该把LIKE这样数据就会出现 例如 如果我这样设置 SEL
  • 什么时候应该在 SQL Server 中使用分号?

    在检查 Web 上的一些代码和 SQL Server Management Studio 生成的脚本时 我注意到某些语句以分号结尾 那么我应该什么时候使用它呢 来自 SQLServerCentral Comarticle http www
  • SQL CASE 语句

    我有以下查询 我想将它们放入 sql CASE 语句中 这样我只有一个查询 但我不知道该怎么做 有人可以帮助我吗 IF SELECT EtlLoadId FROM ssislogs audit processcontrol WHERE Su
  • 仅选择一半记录

    我试图弄清楚如何选择 ID 为空的一半记录 我想要一半 因为我将使用该结果集来更新另一个 ID 字段 然后我将使用该 ID 字段的另一个值更新其余部分 所以本质上我想用一个数字更新一半记录 someFieldID 用另一个数字更新其余记录
  • 批量更新 SQL Server C#

    我有一个 270k 行的数据库 带有主键mid和一个名为value 我有一个包含中值和值的文本文件 现在我想更新表格 以便将每个值分配给正确的中间值 我当前的方法是从 C 读取文本文件 并为我读取的每一行更新表中的一行 必须有更快的方法来做

随机推荐

  • 如何在 ClickOnce 应用程序的无签名程序集项目中设置 LARGEADRESSAWARE?

    我有一个带有接下来两个编译后命令的应用程序 call editbin LARGEADDRESSAWARE TargetPath call editbin LARGEADDRESSAWARE ProjectDir obj PlatformNa
  • 樱桃皮和wxpython

    我正在尝试使用 wxpython ui 制作一个cherrypy 应用程序 问题是两个库都使用闭环事件处理程序 有办法让它发挥作用吗 如果我有 wx ui startcherrypy 会锁定 ui 吗 请参阅我的回答CherryPy 干扰
  • 如何将 csv 文件从 google 云端硬盘上传(并使用它)到 google colaboratory

    想尝试一下 python 和 google colaboratoryseemed最简单的选择 我的谷歌驱动器中有一些文件 想将它们上传到谷歌合作实验室 所以这是我正在使用的代码 pip install U q PyDrive from py
  • Jquery .ajax() 本地测试

    我有一个小的 ajax 函数 它尝试在文档准备好后加载一些内容 document ready function ajax url php accounts blocks php cache false beforeSend function
  • 从 Javascript 触发回发

    好的 我知道这个问题已经被问了很多次 并且我在网上找到了大量有关此问题的信息 不幸的是 这些似乎都不适合我 基本上 我运行一些 JavaScript 来响应用户事件 JavaScript 获取一些信息 一个 int 然后我想将其返回到服务器
  • Google Map API v3 ~ 只需关闭信息窗口?

    尝试简单地关闭信息窗口 我已经有了一系列标记 所以像这样的东西会很好 谢谢 MyMarkers i infowindow close 随着v3 API http code google com apis maps documentation
  • 在一列或多列中查找独特的单词?

    我正在考虑在我的 ASP NET 网站中实现标签 在研究了几种算法之后 我倾向于拥有几个包含一个或多个标签词的数据库列 然后 我将使用全文搜索来查找具有指定标签的行 所有这一切看起来都非常简单 除了一件事 我需要能够生成可用标签列表 用户可
  • R - 按组有条件地对多列进行升序或降序排序

    我以前没有遇到过这个问题 我想根据条件对组内的多列进行升序或降序排序 library dplyr data lt mtcars gt select mpg cyl disp If cyl lt 4 我想排序mpg disp 按该优先级 按升
  • BB10 Cascade 命令行开发

    如果您了解 Qt 那么 BB10 的编程现在应该会容易得多 所以我决定尝试一下 并且我一直在阅读以下内容 https developer blackberry com cascades documentation getting start
  • 在图形环境中,术语“橡皮筋”是什么意思?

    在不同的地方 我都看到过在指代图形绘制时使用的术语 橡皮筋 在这种情况下 人们似乎建议使用 XOR 进行绘图 我的印象是该术语指的是一种用于避免重新绘制整个框架的特定绘图技术 然而 我还没有找到任何可以准确定义 橡皮筋 一词含义的内容 只是
  • 构造函数作为委托 - 在 C# 中可能吗?

    我有一个如下所示的课程 class Foo public Foo int x 我需要将委托传递给某个方法 如下所示 delegate Foo FooGenerator int x 是否可以直接将构造函数作为FooGenerator值 无需输
  • JavaScript getter 和 setter - 递归问题

    JavaScript 的 setter 和 getter 中的 字符有何意义 例如 我有以下代码 可以正常工作 var user get name return this name set name value this name valu
  • 具有通配符属性名称和特定属性值的 C# 和 XPath

    我可以使用 XPath 查找具有名称以特定字符集开头且属性值包含特定值的属性的所有元素吗 例如
  • 调用验证后容器不会调整自身大小

    通过手动交换组件后add and remove 我调用validate 在容器上 根据文档 validate 方法用于使容器布置它的 再次子组件 当该容器的 子组件被修改 添加到容器或从容器中删除 或者 布局相关信息已更改 容器已被 显示
  • 使用 WordApi 1.3 时 context.application 未定义

    使用 WordApi 1 3 应该可以使用新的创建文档方法 https github com OfficeDev office js docs blob WordJs 1 3 Openspec reference word applicat
  • Clojure 模型-视图-控制器 (MVC) 设计

    我正在使用 Java Swing 在 Clojure 中编写桌面 GUI 应用程序 通常 在使用 Java 时 我会根据 MVC 设计模式并使用观察者模式来设计应用程序 通过这种方式 视图与模型分离 并且两者的更改不会相互影响 从而使进一步
  • 在每种情况下使用带有值范围的 switch 语句?

    在Java中 是否可以编写一个switch语句 其中每个case包含多个值 例如 尽管显然以下代码不起作用 switch num case 1 5 System out println testing case 1 to 5 break c
  • PyCUDA/CUDA:不确定性启动失败的原因?

    任何关注 CUDA 的人可能都会看到我对我所参与的项目提出的一些疑问 但对于那些没有见过的人 我将进行总结 抱歉提前问了一个很长的问题 三个内核 一个基于一些输入变量生成数据集 处理位组合 因此可以呈指数增长 另一个解决这些生成的线性系统
  • 如何使用 Spray.io 构建 RESTful API?

    当我使用 Spray io 开发 RESTful API 时 我应该如何构建我的应用程序 我已经看到了这个答案 https stackoverflow com a 14653989 396002关于如何拆分 Spray 应用程序 但我对此不
  • 什么时候不应该使用分号?

    Or 什么不是 T SQL 语句 除了解决歧义之外 T SQL 语法不需要分号来终止语句 尽管如此 伊齐克 本 甘 http www sqlmag com blog puzzled by t sql blog 15 tsql semicol