【问题标题】:How to ignore the GO statements in IF EXISTS block?如何忽略 IF EXISTS 块中的 GO 语句?
【发布时间】:2021-02-03 20:35:07
【问题描述】:

我正在尝试根据 IF NOT EXISTS 条件执行脚本。但是,即使 IF NOT EXISTS 返回 1,BEGIN 和 END 中的块也会执行。我无法更改 BEGIN 和 END 块中的语句。这种情况如何处理?

IF NOT EXISTS(SELECT 1 FROM [dbo].[UPGRADEHISTORY] WHERE SCRIPTNAME='001-MarkSubmitted.sql' AND RELEASENUMBER= '1')
BEGIN
    IF NOT EXISTS(SELECT 1 FROM [dbo].[Action] WHERE Name='mark As Submitted')
        BEGIN
        SET IDENTITY_INSERT [dbo].[Action] ON 
        INSERT INTO [dbo].[Action](Id,Name,CreatedBy,CreatedOn) VALUES (6,'mark As Submitted',1,getdate())
        SET IDENTITY_INSERT [dbo].[Action] OFF
        END
    GO
    INSERT INTO [dbo].[StatusActionMapping](ArtifactType,StatusId,ActionId,RoleId) VALUES ('Report',11,6,1)
    GO

    INSERT INTO [dbo].[UpgradeHistory] ([ReleaseNumber],[ScriptNumber],[ScriptName],[ExecutionDate]) VALUES (1, (SELECT FORMAT(MAX(SCRIPTNUMBER) + 1, 'd3') FROM UpgradeHistory WHERE ReleaseNumber= 1),'001-MarkSubmitted.sql',GETDATE());
END
GO

【问题讨论】:

  • GO 不是 T-SQL 运算符,它被 IDE/CLI 解释为批处理分隔符。如果您不想将语句分成单独的批次(显然在这里您不想),请不要将GOs 放在那里。解决方案很简单,通过删除它们来修复你的代码,因为如果你要将它们分成真正的单独批次(即单独的文件),那么你所拥有的语法是无效的。
  • 我无法删除 BEGIN 和 END 块中的 GO 语句。问题是即使 NOT EXISTS 为 1 也会执行语句
  • “我不能删除 BEGIN 和 END 块中的 GO 语句。” 为什么不呢?为什么要在 BEGIN...END 的中间分开一个批次?

标签: sql sql-server


【解决方案1】:

正如我在评论中提到的,GO 不是 Transact-SQL 运算符,它被您的 IDE/CLI 解释为批处理分隔符。SQL Server Utilities Statements - GO

SQL Server 提供的命令不是 Transact-SQL 语句,但可以被 sqlcmd 和 osql 实用程序以及 SQL Server Management Studio 代码编辑器识别。这些命令可用于促进批处理和脚本的可读性和执行。

GO 向 SQL Server 实用程序发出一批 Transact-SQL 语句结束的信号。

答案很简单,删除GOs。这里不需要它们; 因为他们在那里你得到了错误,因为将语句分成不同的批次在这里没有意义。你所拥有的相当于拥有以下 3 个“文件”并尝试独立运行它们:

文件 1:

IF NOT EXISTS(SELECT 1 FROM [dbo].[UPGRADEHISTORY] WHERE SCRIPTNAME='001-MarkSubmitted.sql' AND RELEASENUMBER= '1')
BEGIN
    IF NOT EXISTS(SELECT 1 FROM [dbo].[Action] WHERE Name='mark As Submitted')
        BEGIN
        SET IDENTITY_INSERT [dbo].[Action] ON 
        INSERT INTO [dbo].[Action](Id,Name,CreatedBy,CreatedOn) VALUES (6,'mark As Submitted',1,getdate())
        SET IDENTITY_INSERT [dbo].[Action] OFF
        END

由于BEGIN 没有END 会导致错误。

文件 2:

INSERT INTO [dbo].[StatusActionMapping](ArtifactType,StatusId,ActionId,RoleId) VALUES ('Report',11,6,1)

这会运行良好。

文件 3:

INSERT INTO [dbo].[UpgradeHistory] ([ReleaseNumber],[ScriptNumber],[ScriptName],[ExecutionDate]) VALUES (1, (SELECT FORMAT(MAX(SCRIPTNUMBER) + 1, 'd3') FROM UpgradeHistory WHERE ReleaseNumber= 1),'001-MarkSubmitted.sql',GETDATE());
END

由于没有BEGINEND 会出错。

您的查询中没有任何内容会导致解析错误,例如您将新列添加到现有表并稍后在批处理中引用它,因此无需分隔批处理。只需删除 BEGIN...ENDs 中间的 GOs 即可满足您的要求:

IF NOT EXISTS (SELECT 1
               FROM [dbo].[UPGRADEHISTORY]
               WHERE SCRIPTNAME = '001-MarkSubmitted.sql'
                 AND RELEASENUMBER = '1')
BEGIN
    IF NOT EXISTS (SELECT 1
                   FROM [dbo].[Action]
                   WHERE Name = 'mark As Submitted')
    BEGIN
        SET IDENTITY_INSERT [dbo].[Action] ON;
        INSERT INTO [dbo].[Action] (Id, Name, CreatedBy, CreatedOn)
        VALUES (6, 'mark As Submitted', 1, GETDATE());
        SET IDENTITY_INSERT [dbo].[Action] OFF;
    END;
    INSERT INTO [dbo].[StatusActionMapping] (ArtifactType, StatusId, ActionId, RoleId)
    VALUES ('Report', 11, 6, 1);

    INSERT INTO [dbo].[UpgradeHistory] ([ReleaseNumber], [ScriptNumber], [ScriptName], [ExecutionDate])
    VALUES (1, (SELECT FORMAT(MAX(SCRIPTNUMBER) + 1, 'd3') --This is a REALLY bad idea. Use an IDENTITY or SEQUENCE
                FROM UpgradeHistory
                WHERE ReleaseNumber = 1), '001-MarkSubmitted.sql', GETDATE());
END;
GO

还请注意我对您最后的INSERT 的看法。 FORMAT(MAX(SCRIPTNUMBER) + 1, 'd3') 以竞争条件结束。使用IDENTITYSEQUENCE

【讨论】:

  • WITH (UPDLOCK, HOLDLOCK) 在第一次选择时会解决竞争条件。但同意,身份插入是个坏主意。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-27
  • 1970-01-01
  • 2017-09-13
  • 2020-10-28
  • 2015-08-13
  • 2014-03-04
  • 1970-01-01
相关资源
最近更新 更多