我正在生成一个脚本,用于自动将更改从多个开发数据库迁移到登台/生产。基本上,它需要一堆更改脚本,并将它们合并到一个脚本中,将每个脚本包装在IF whatever BEGIN ... END
语句中。
但是,某些脚本需要GO
语句,因此,例如,SQL解析器在创建新列后会知道它。
ALTER TABLE dbo.EMPLOYEE
ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO -- Necessary, or next line will generate "Unknown column: EMP_IS_ADMIN"
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever
然而,一旦我将其包裹在IF
块中:
IF whatever
BEGIN
ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever
END
它失败了,因为我发送的BEGIN
没有匹配END
。但是,如果我删除GO
,它会再次抱怨未知列。
有没有办法在一个IF
块中创建和更新同一列?
答案 0 :(得分:39)
GO
不是SQL - 它只是某些MS SQL工具中使用的批处理分隔符。
如果不使用它,则需要确保语句单独执行 - 分批执行或使用动态SQL进行填充(感谢@gbn):
IF whatever
BEGIN
ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL;
EXEC ('UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever')
END
答案 1 :(得分:32)
我遇到了同样的问题,最后设法使用 SET NOEXEC 解决了这个问题。
IF not whatever
BEGIN
SET NOEXEC ON;
END
ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever
SET NOEXEC OFF;
答案 2 :(得分:16)
您可以尝试sp_executesql
,将每个GO
语句之间的内容拆分为要执行的单独字符串,如下例所示。此外,还有一个@statementNo变量来跟踪正在执行哪个语句,以便在出现异常时进行简单调试。行号将相对于导致错误的相关语句编号的开头。
BEGIN TRAN
DECLARE @statementNo INT
BEGIN TRY
IF 1=1
BEGIN
SET @statementNo = 1
EXEC sp_executesql
N' ALTER TABLE dbo.EMPLOYEE
ADD COLUMN EMP_IS_ADMIN BIT NOT NULL'
SET @statementNo = 2
EXEC sp_executesql
N' UPDATE dbo.EMPLOYEE
SET EMP_IS_ADMIN = 1'
SET @statementNo = 3
EXEC sp_executesql
N' UPDATE dbo.EMPLOYEE
SET EMP_IS_ADMIN = 1x'
END
END TRY
BEGIN CATCH
PRINT 'Error occurred on line ' + cast(ERROR_LINE() as varchar(10))
+ ' of ' + 'statement # ' + cast(@statementNo as varchar(10))
+ ': ' + ERROR_MESSAGE()
-- error occurred, so rollback the transaction
ROLLBACK
END CATCH
-- if we were successful, we should still have a transaction, so commit it
IF @@TRANCOUNT > 0
COMMIT
您也可以轻松执行多行语句,如上例所示,只需将它们包装在单引号('
)中即可。生成脚本时,不要忘记使用双引号(''
)转义字符串中包含的任何单引号。
答案 3 :(得分:8)
我最终通过用
替换自己行中GO
的每个实例来实现它
END
GO
---Automatic replacement of GO keyword, need to recheck IF conditional:
IF whatever
BEGIN
这比将每组语句包装在一个字符串中更好,但仍然远。如果有人找到更好的解决方案,请发布它,我会接受它。
答案 4 :(得分:7)
您可以将语句括在BEGIN和END中,而不是GO中间
IF COL_LENGTH('Employees','EMP_IS_ADMIN') IS NULL --Column does not exist
BEGIN
BEGIN
ALTER TABLE dbo.Employees ADD EMP_IS_ADMIN BIT
END
BEGIN
UPDATE EMPLOYEES SET EMP_IS_ADMIN = 0
END
END
(在Northwind数据库上测试)
编辑:(可能在SQL2012上测试)
答案 5 :(得分:0)
我过去曾为此使用RAISERROR
IF NOT whatever BEGIN
RAISERROR('YOU''RE ALL SET, and sorry for the error!', 20, -1) WITH LOG
END
ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever
答案 6 :(得分:0)
您可以尝试以下解决方案:
if exists(
SELECT...
)
BEGIN
PRINT 'NOT RUN'
RETURN
END
--if upper code not true
ALTER...
GO
UPDATE...
GO
答案 7 :(得分:-1)
您可以合并GOTO
和LABEL
语句来跳过代码,从而保留GO
个关键字。