2013-08-27 5 views
24

Ich habe (zu Testzwecken) viele dbs mit dem gleichen Schema (= gleiche Tabellen und Spalten im Grunde) auf einer SQL Server 2008 R2-Instanz.Wie wird dieselbe Abfrage für alle Datenbanken einer Instanz ausgeführt?

ich möchte eine Abfrage wie

SELECT COUNT(*) FROM CUSTOMERS 

auf alle DBs auf der Instanz. Ich möchte als Ergebnis 2 Spalten haben:

1 - der DB-Name

2 - der Wert COUNT(*)

Beispiel:

DBName // COUNT (*) 

TestDB1 // 4 

MyDB // 5 

etc... 

Anmerkung: Ich gehe davon aus, dass CUSTOMERS Tabelle vorhanden in allen dbs (außer master).

Antwort

31

Versuchen Sie dieses -

SET NOCOUNT ON; 

IF OBJECT_ID (N'tempdb.dbo.#temp') IS NOT NULL 
    DROP TABLE #temp 

CREATE TABLE #temp 
(
     [COUNT] INT 
    , DB VARCHAR(50) 
) 

DECLARE @TableName NVARCHAR(50) 
SELECT @TableName = '[dbo].[CUSTOMERS]' 

DECLARE @SQL NVARCHAR(MAX) 
SELECT @SQL = STUFF((
    SELECT CHAR(13) + 'SELECT ''' + name + ''', COUNT(1) FROM [' + name + '].' + @TableName 
    FROM sys.databases 
    WHERE OBJECT_ID(name + '.' + @TableName) IS NOT NULL 
    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') 

INSERT INTO #temp (DB, [COUNT])    
EXEC sys.sp_executesql @SQL 

SELECT * 
FROM #temp t 

Ausgang (zum Beispiel in AdventureWorks) -

COUNT  DB 
----------- -------------------------------------------------- 
19972  AdventureWorks2008R2 
19975  AdventureWorks2012 
19472  AdventureWorks2008R2_Live 
+0

Hallo Devart, ich benutze diese SQL und funktioniert gut. Ist es jedoch möglich, eine Prüfung hinzuzufügen, wenn der Benutzer, der diese Abfrage ausführt, Zugriff auf jede Datenbank hat oder nicht, und wenn dies nicht der Fall ist, sollte die Abfrage weiterhin ausgeführt werden und nur die Datenbanken zurückgeben, auf die der Benutzer Zugriff hat. Was ich danach suche, ist, ob der Benutzer DBO-Rollenrechte für jede der Datenbanken hat und wenn nicht, gehe zum nächsten. Bitte berate dich. – DK2014

23

Straight forward Abfrage

EXECUTE sp_MSForEachDB 
     'USE ?; SELECT DB_NAME()AS DBName, 
     COUNT(1)AS [Count] FROM CUSTOMERS' 

Diese Abfrage wird Ihnen zeigen, was Sie sehen wollen, sondern auch ohne Tisch Fehler für jeden DB werfen genannten „KUNDEN“. Sie müssen eine Logik erarbeiten, um damit umzugehen.

Raj

+1

+1 es ist eine sehr kompakte Lösung, aber ich cho Die andere, da Ihre Lösung viele Ergebnistabellen kettet, während die andere nicht – LaBracca

+3

Erwähnenswert ist, dass die sp_MSForEachDB nicht dokumentiert ist, nicht unterstützt wird und einige bekannte Probleme hat, wie von Aaron Bertrand hier http://sqlblog.com/blogs/aaron_bertrand diskutiert /archive/2010/12/29/a-more-reliable-and-more-flexible-sp-msforeachdb.aspx. –

5

Wie wäre es etwa so:

DECLARE c_db_names CURSOR FOR 
SELECT name 
FROM sys.databases 
WHERE name NOT IN('master', 'tempdb') --might need to exclude more dbs 

OPEN c_db_names 

FETCH c_db_names INTO @db_name 

WHILE @@Fetch_Status = 0 
BEGIN 
    EXEC(' 
    INSERT INTO #report 
    SELECT 
     ''' + @db_name + ''' 
     ,COUNT(*) 
    FROM ' + @db_name + '..linkfile 
    ') 
    FETCH c_db_names INTO @db_name 
END 

CLOSE c_db_names 
DEALLOCATE c_db_names 

SELECT * FROM #report 
+0

Dies ist ein nützliches generelles Snippet, ich habe gerade 'sys.databases' durch' sys.tables' für einen ganz anderen Zweck ersetzt, indem ich das gleiche Beispiel verwende. –

+2

Sie haben im Skript vergessen, [at] db_name zu deklarieren, müssen Sie eine Zeile hinzufügen: DECLARE @db_name NVARCHAR (150), ansonsten sehr nützlich Skript :-) – inkubpl

+0

Wo ist die temporäre Tabelle delcared? – Phil3992