29 septembre 2013

SQL : Exécuter une requête sur toutes les bases d'un serveur

Exécuter une même requête SQL Server sur quelques (ou toutes les) tables d'un serveur ?

La procédure sp_msforeachdb (non documentée) peut aider :

EXEC sp_msforeachdb '
USE [?]; 
IF (''?'' LIKE ''m%'' AND EXISTS (SELECT 1 FROM sys.tables WHERE name = ''object''))
BEGIN 
 Print ''?'' + '' as not object''
END;

'

L'argument chaîne se décompose en :

  • USE ==> pour basculer sur la base.  ? est le nom de la base en cours. Notez les [] qui encadrent le ?
  • IF ==> 
           1) tester la ou les bases qui nous intéressent (pourrait être fait avant le use) 
           2) tester s'il y a ce qu'il faut dans la base pour que la requête fonctionne
  • Entre le BEGIN et le END ==> la requête à exécuter.
On peut aussi créer une table temporaire avant l'exécution de cette requête et y agréger les résultat par un insert au lieu d'un sélect. On obtient ainsi une seule table de données :

CREATE TABLE #tmp (base VARCHAR(50) NOT NULL, nombre INT NOT NULL);

EXEC sp_msforeachdb '
Use [?]; 
IF (''?'' LIKE ''m%'' AND EXISTS (SELECT 1 FROM sys.tables WHERE name = ''object''))
BEGIN 
 INSERT INTO #tmp (base, nombre) SELECT ''?'' AS base, COUNT(*) FROM sys.tables
END;
'
SELECT * FROM #tmp;


Attention selon les colonnes présente ou pas dans la base certaine requête pourraient planter. 
Pour contourner ce problème voici un exemple :

EXEC sp_msforeachdb '
USE [?]; 
IF (''?'' LIKE ''mes_bases_%'' AND EXISTS (SELECT 1 FROM sys.tables t INNER JOIN sys.columns c ON t.object_id = c.object_id WHERE t.name = ''table1'' AND c.name = ''colonne_qui_est_pas_dans_toutes_les_bases'')  )
BEGIN 
   Declare @msg varchar(max)
   SET @msg = ''SELECT ''''?'''' as base, count(*) as nombre FROM table1 WHERE colonne_qui_est_pas_dans_toutes_les_bases is not null'';
   EXEC (@msg);
END;
'

Comptez bien le nombre d'apostrophes !!!!



Enjoy;


Aucun commentaire:

Enregistrer un commentaire