Использование SQL Server sp msforeachtable для выбора только тех таблиц, которые удовлетворяют некоторым условиям

Я пытаюсь написать этот запрос, чтобы найти все таблицы с определенным столбцом с определенным значением. Вот что я сделал до сих пор ... --6-->

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+''')'

2 ответов


ты знаешь, как sp_MSforeachtable является недокументированным и может уйти в любое время/быть изменен?

Ну, если вы счастливы игнорировать это, у него есть другой параметр под названием @whereand, который прилагается к WHERE предложение внутреннего запроса, который используется для поиска таблиц (и должен начинаться с AND).

вы также должны знать, что есть псевдоним, o против sysobjects, и второй псевдоним syso против sys.all_objects.

С помощью этого знание, вы могли бы создать свой @whereand параметр as:

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

теперь вы можете упростить ваш command1, так как вы знаете, что он будет работать только против таблиц, содержащих . Я бы, наверное, вынул 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, так как вы не хотите заменить значение там).

проблема в том, что вы можете пройти параметры в хранимой процедуре, или литералы, но вы не можете выполнять вычисления/комбинировать действия между ними - поэтому я переместил построение инструкции sql в отдельное действие.


Я думаю, вы получаете какую-то ошибку, возможно 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
'