【问题标题】:SQL Server sp_msforeachtable usage to select only those tables which meet some conditionSQL Server sp_msforeachtable 用法仅选择满足某些条件的表
【发布时间】:2012-03-29 14:46:33
【问题描述】:

我正在尝试编写此查询来查找具有特定列和特定值的所有表。这就是我到目前为止所做的 -

EXEC sp_MSforeachtable 
@command1='
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=PARSENAME("?",2) AND TABLE_NAME=PARSENAME("?",1) AND COLUMN_NAME="EMP_CODE")
BEGIN
    IF (SELECT COUNT(*) FROM ? WHERE EMP_CODE="HO081")>0
    BEGIN
        SELECT * FROM ? WHERE EMP_CODE="HO081"
    END
END
'

我希望我的意图很明确,我只想选择那些存在EMP_CODE 列的表,并且在这些表中我想选择那些存在EMP_CODE='HO081' 的行。

编辑 -

现在它是这样的。但我无法替换查询中的@EMPCODE 变量。

DECLARE @EMPCODE AS VARCHAR(20)
SET @EMPCODE='HO081'
EXEC sp_MSforeachtable 
@command1='
    DECLARE @COUNT AS INT
    SELECT @COUNT=COUNT(*) FROM ? WHERE EMP_CODE='''+@EMPCODE+'''
    IF @COUNT>0
    BEGIN
        PRINT PARSENAME("?",1)+'' => ''+CONVERT(VARCHAR,@COUNT)+'' ROW(S)''
        --PRINT ''DELETE FROM ''+PARSENAME("?",1)+'' WHERE EMP_CODE='''''+@EMPCODE+'''''''
    END
',@whereand='AND O.ID IN (SELECT OBJECT_ID FROM SYS.COLUMNS C WHERE C.NAME='''+@EMPCODE+''')'

【问题讨论】:

    标签: sql-server sql-server-2008 stored-procedures sql-server-2005 sp-msforeachtable


    【解决方案1】:

    您知道sp_MSforeachtable 是如何无证的,并且可能随时消失/被修改吗?

    好吧,如果您愿意忽略它,它还有另一个名为 @whereand 的参数,它附加到用于查找表的内部查询的 WHERE 子句(并且应该以AND)。

    您还必须知道有一个别名,o 与 sysobjects,以及第二个别名 syso 与 sys.all_objects。

    利用这些知识,您可以将@whereand 参数设计为:

    EXEC sp_MSforeachtable 
    @command1='...',
    @whereand='AND o.id in (select object_id from sys.columns c where c.name=''EMP_CODE'')'
    

    您现在还可以简化您的command1,因为您知道它只会针对包含EMP_CODE 列的表运行。我可能也会去掉COUNT(*) 条件,因为我看不出它增加了什么价值。


    根据您的进一步工作进行了更新,并针对一张表进行了测试:

    DECLARE @EMPCODE AS VARCHAR(20)
    SET @EMPCODE='HO081'
    declare @sql nvarchar(2000)
    set @sql = '
        DECLARE @COUNT AS INT
        SELECT @COUNT=COUNT(*) FROM ? WHERE EMP_CODE='''+@EMPCODE+'''
        IF @COUNT>0
        BEGIN
            PRINT PARSENAME("?",1)+'' => ''+CONVERT(VARCHAR,@COUNT)+'' ROW(S)''
            --PRINT ''DELETE FROM ''+PARSENAME("?",1)+'' WHERE EMP_CODE='''''+@EMPCODE+'''''''
        END
    '
    EXEC sp_MSforeachtable 
    @command1=@sql,@whereand='AND O.ID IN (SELECT OBJECT_ID FROM SYS.COLUMNS C WHERE C.NAME=''EMP_CODE'')'
    

    (我已将@whereand 还原为查询EMP_CODE,因为您不想替换那里的值)。

    问题是,您可以将 parameters 传递给存储过程或 literals,但不能在它们之间执行计算/组合操作 - 所以我移动了将sql语句构造成单独的action。

    【讨论】:

    • +1 向您展示您可以做什么,但含蓄地告诉您不要这样做;)
    • @Damien_The_Unbeliever 假设如果我写 IF (SELECT COUNT(*) FROM ? WHERE EMP_CODE='''+@EMPCODE+''')>0 那么它为什么会给我 - + 附近的语法不正确。我正在尝试通过变量传递 EMP_CODE 值。
    • @SohamDasgupta - 在 cmets 部分诊断这种问题有点棘手,因为我真的需要查看现在的整个查询,这在厘米。不过,我会再次查询那段特定的代码 - 为什么 count 匹配行的数量而不是简单地选择它们?空结果集通常很容易处理。
    • @Damien_The_Unbeliever 我在问题中发布了新查询。请通过。
    • @SohamDasgupta - 在我的答案底部添加了一个更新的示例,并解释了为什么它是必要的。我想第三次问你为什么在采取任何进一步行动之前执行COUNT - 运行SELECT(根据你原来的问题)或DELETE(根据您的更新),这实际上不会影响任何行。首先执行COUNT 是多余的,可能会导致查询需要更多时间来执行。
    【解决方案2】:

    我猜你得到了某种错误,也许是Invalid column name 'EMP_CODE'?

    这是因为代码是在您检查列之前编译的。 你可以这样做。

    EXEC sp_MSforeachtable 
    @command1='
    IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=PARSENAME("?",2) AND TABLE_NAME=PARSENAME("?",1) AND COLUMN_NAME="EMP_CODE")
    BEGIN
       EXEC(''
              IF (SELECT COUNT(*) FROM ? WHERE EMP_CODE="HO081")>0
              BEGIN
                  SELECT * FROM ? WHERE EMP_CODE="HO081"
              END
            '')
    END
    '
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-02
      • 1970-01-01
      • 2014-07-17
      • 2014-02-18
      • 2020-08-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多