我有一种情况,我想检查某个列(如版本号),然后应用一堆ddl更改
麻烦是我无法在IF BEGIN END块中执行此操作,因为DDL语句需要在它们之间使用GO分隔符,而TSQL不允许这样做。
我想知道是否有办法完成这个
答案 0 :(得分:6)
您不需要使用完整的块。如果您不使用BEGIN / END(包括单个DDL语句),则条件将完整地执行下一个语句。这相当于Pascal,C等中 if 的行为。当然,这意味着您将不得不一遍又一遍地重新检查您的状况。这也意味着使用变量来控制脚本的行为几乎是不可能的。
[编辑:CREATE PROCEDURE在下面的示例中不起作用,因此我将其更改为其他内容并移动了CREATE PROCEDURE以进行下面的更广泛讨论]
If ((SELECT Version FROM table WHERE... ) <= 15)
CREATE TABLE dbo.MNP (
....
)
GO
If ((SELECT Version FROM table WHERE... ) <= 15)
ALTER TABLE dbo.T1
ALTER COLUMN Field1 AS CHAR(15)
GO
...
或类似的东西,取决于你的情况。
不幸的是,CREATE / ALTER PROCEDURE和CREATE / ALTER VIEW有特殊要求,这使得它更难以使用。它们几乎被要求成为声明中唯一的东西,所以你根本不能将它们与IF结合起来。
对于许多场景,当您想要“升级”对象时,可以将其作为条件下拉,然后创建:
IF(EXISTS(SELECT * FROM sys.objects WHERE type='p' AND object_id = OBJECT_ID('dbo.abc')))
DROP PROCEDURE dbo.abc
GO
CREATE PROCEDURE dbo.abc
AS
...
GO
如果确实需要条件逻辑来决定做什么,那么我所知道的唯一方法是使用EXECUTE以字符串形式运行DDL语句。
If ((SELECT Version FROM table WHERE... ) <= 15)
EXECUTE 'CREATE PROC dbo.abc
AS
....
')
但这非常痛苦。你必须逃避程序正文中的任何引号,这真的很难读。
根据您需要应用的更改,您可以看到所有这些变得非常难看。以上甚至不包括错误检查,这本身就是一种皇家的痛苦。这就是为什么成群的工具制造者通过找出自动创建部署脚本的方法来谋生。
抱歉;对于一切都没有简单的“正确”方式。这只是TSQL非常糟糕的支持。不过,上述应该是一个良好的开端。
答案 1 :(得分:1)
GO由客户端工具识别,而不是由服务器识别。 您可以在存储过程中使用CREATE,也可以在没有GO的情况下进行临时查询。
答案 2 :(得分:1)
多个“IF”声明?然后,您可以测试后续DDL语句是否成功
动态SQL? EXEC('ALTER TABLE foo with CHECK ADD CONSTRAINT ...')?
如上所述,GO是一个仅客户端批处理分隔符,用于将单个SQL文本块分解为提交给SQL Server的批处理。