Utilisation MSFOREACHTABLE de SQL Server sp pour sélectionner seulement les tables qui répondent à certaines conditions
j'essaie d'écrire cette requête pour trouver toutes les tables avec une colonne spécifique avec une valeur spécifique. C'est ce que j'ai fait jusqu'à présent -
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
'
j'espère que mes intentions sont claires, je veux juste sélectionner seulement les tableaux où la colonne EMP_CODE
est présent, et dans ces tables, je veux sélectionner les lignes où EMP_CODE='HO081'
.
Edit -
maintenant c'est comme ça. Mais je ne suis pas en mesure de remplacer @EMPCODE
variable dans le requête.
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 réponses
Vous savez comment sp_MSforeachtable
est sans-papiers, et peuvent disparaître à tout moment, être modifié?
Eh bien, si vous êtes heureux d'ignorer cela, il a un autre paramètre appelé @whereand
, qui est ajouté au WHERE
l'article de la requête interne qui est utilisé pour trouver les tables (et doit commencer par AND
).
Vous devez aussi savoir qu'il y a un alias, o
contre sysobjects
, et un second alias syso
contre sys.all_objects
.
en utilisant ceci de connaissances, vous pouvez créer votre @whereand
paramètre:
EXEC sp_MSforeachtable
@command1='...',
@whereand='AND o.id in (select object_id from sys.columns c where c.name=''EMP_CODE'')'
vous pouvez maintenant aussi simplifier votre command1
, puisque vous savez qu'il ne sera exécuté que contre des tables contenant un EMP_CODE
colonne. J'enlèverais probablement le COUNT(*)
condition aussi, puisque je ne vois pas quelle valeur il ajoute.
mise à Jour basé sur la poursuite de votre travail, et testé contre une table:
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'')'
(j'ai inversé le @whereand
à la requête pour EMP_CODE
, puisque vous ne voulez pas remplacer la valeur y).
Le problème est que, vous pouvez passer paramètres pour une procédure stockée, ou littéraux, mais vous ne pouvez pas effectuer des calculs / combiner des actions entre eux-donc j'ai déplacé la construction de la déclaration sql dans une action séparée.
je suppose que tu auras une erreur de quelque sorte, peut-être Invalid column name 'EMP_CODE'
?
c'est parce que le code est compilé avant de vérifier la colonne. Tu pourrais faire comme ça à la place.
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
'