SQL Server:检查表列是否存在并删除行

SQL Server : check if table column exists and remove rows

我目前正在编写一个通用的SQL Server脚本来清理具有相同表结构的不同数据库。此脚本要求如果数据库中存在某个表,我将清除该表中的某些数据。这里是脚本的一个示例

1
2
3
IF EXISTS( SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'TAB1')
  IF EXISTS( SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'TAB1' AND  COLUMN_NAME = 'COL1')
    DELETE TAB1 WHERE COL1 NOT IN (SELECT COL2 FROM TAB2);

作为一个程序员,我知道如果两个条件块都为假,则不会执行delete命令。但是,当我在SQL中运行它时,它返回

Invalid column name 'COL1'.

可能我的方法不对。有人能告诉我正确的方向吗?


问题是,SQL Server希望在执行任何批处理之前编译整个批处理。

它无法编译批处理,因为缺少列。

因此,您必须确保批处理可以编译,而不必尝试编译DELETE语句,因此将其作为字符串保存并强制单独编译:

1
2
3
4
IF EXISTS( SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'TAB1')
  IF EXISTS( SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'TAB1'
        AND  COLUMN_NAME = 'COL1')
    EXEC sp_executesql 'delete TAB1 where COL1 not in (select COL2 from TAB2);'

你说:

As a programmer, I know that the delete command will not be executed if both condition block are false.

假设您的原始查询是一个C背景,那么您的原始查询就像执行两个反射调用来确定一个类型是否具有特定的属性,然后在该类型的对象上直接使用该属性的一行代码-如果该类型没有该属性,则代码不会编译,因此反射检查永远不会有执行的机会。


试试这个-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
DECLARE
       @COLUMN SYSNAME = 'COL1'
     , @TABLE SYSNAME = 'dbo.TAB1'
     , @SQL NVARCHAR(MAX)

IF EXISTS (
     SELECT 1
     FROM sys.columns c
     WHERE c.[object_id] = OBJECT_ID(@TABLE)
          AND c.name = @COLUMN
) BEGIN

     SELECT @SQL = '
          DELETE TAB1
          WHERE COL1 NOT IN (SELECT COL2 FROM TAB2)'


     EXEC sys.sp_executesql @SQL

END