Bla*_*ter 1 sql-server t-sql sql-server-2017
我有一种情况,我需要对大量类似的数据库运行查询。他们中的大多数人都会有一个表,我需要更新其中的一些行,但其中一些人没有该表。
我想编写一个查询,该查询具有IF
检查表是否存在EXEC sp_executesql
的UPDATE
语句,而无需使用该语句。有没有办法在 SQL Server 中做到这一点?
这是我今天正在做的一个例子:
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[MyTableName]') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN
-- this is what I want to be able to do but cannot
UPDATE [dbo].[MyTableName] SET [SomeColumn] = NULL WHERE [SomeColumn] NOT IN (1, 2, 3)
-- this is the only way I know to do this without an error
EXEC sp_executesql N'UPDATE [dbo].[MyTableName] SET [SomeColumn] = NULL WHERE [SomeColumn] NOT IN (1, 2, 3)'
END
Run Code Online (Sandbox Code Playgroud)
如果语句检查现有的不同表并更新它们,但批处理中没有其他逻辑,我可能有更多的副本。没有sp_executesql
它会给我一个关于表不存在的错误,因为它需要在评估IF
语句之前编译整个批处理。
我不是特别反对sp_executesql
,而是一般反对动态 SQL。我想要一个解决方案,它不需要我将内部查询编码/转义为字符串,并允许我在编写内部查询时使用 IDE 提供语法突出显示和自动完成。
这里的问题是 SQL Server 在解析 SQL 语句时验证对象,因此如果对象不存在,它就会失败,但是,有一个技巧可以解决这个问题。
SQL Server 分析 IF 语句中的对象名称,但不验证 ELSE 部分中的对象。不是检查对象是否存在,如果存在则采取行动,而是检查对象是否不存在,如果存在则采取行动。
例子:
CREATE TABLE TestTable1 (RowData VARCHAR(255))
GO
INSERT INTO TestTable1 VALUES ('Test data')
GO
IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TestTable2')
BEGIN
PRINT 'Table does not exist'
END
ELSE
BEGIN
UPDATE TestTable2
SET RowData = 'Text update'
END
IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TestTable1')
BEGIN
PRINT 'Table does not exist'
END
ELSE
BEGIN
UPDATE TestTable1
SET RowData = 'Text update'
END
Run Code Online (Sandbox Code Playgroud)
在示例中,TestTable2 不存在,但是脚本仍然执行,因为在 IF 语句的 ELSE 部分中引用了缺少的表。这允许脚本被解析,并且当它被执行时,它永远不会到达脚本中缺少对象的部分,因此不会导致错误。