2011-01-18 13 views
6

Mi chiedevo se qualcuno potesse aiutarmi a creare un ciclo while per iterare attraverso diversi database per ottenere dati da una tabella da due colonne. questo è stato che ho fatto finora. niente funziona perché non so come fare il lavoro di selezione dichiarazione attraverso ogni database per quanto riguarda il tavolo che sto l'interrogazione da ogni database (dbo.tbldoc)While Loop to Iterate through Database

DECLARE @Loop int 
DECLARE @DBName varchar(300) 
DECLARE @SQL varchar(max) 
DECLARE @tableName VARCHAR(255) 

SET @Loop = 1 
SET @DBName = '' 

    WHILE @Loop = 1 
BEGIN 

    SELECT [name] FROM sys.databases 
    WHERE [name] like 'z%' and create_date between '2010-10-17' and '2011-01-15' 
    ORDER BY [name] 

     SET @Loop = @@ROWCOUNT 

    IF @Loop = 0 
     BREAK 

    SET @SQL = ('USE ['+ @DBNAME +']') 
     IF EXISTS(SELECT [name] FROM sys.tables WHERE name != 'dbo.tbldoc') 
        BEGIN 
       SELECT SUM(PGCOUNT), CREATED FROM **dbo.tbldoc** 
      END 
      ELSE 
      --BEGIN 
       PRINT 'ErrorLog' 
      END 

risposta

27

vorrei prendere in considerazione sp_MSForEachDB che è molto più facile ...

Edit:

sp_MSForEachDB 'IF DB_NAME LIKE ''Z%%'' 
BEGIN 


END 
' 
+0

non visualizza tutti i database? sto solo interrogando database che iniziano con 'Z' – Jeff

+0

Sì, lo è, ma dovresti inserire i dati risultanti nel codice superiore in una tabella e filtrare dopo quello con il nome db. – Marian

+0

come funziona questa procedura? – Jeff

-1

non è necessario utilizzare un'istruzione "USE DATABASE". È possibile scegliere tra la particolare tabella di database utilizzando un identificativo 3 parte come in:

select * from MyDatabase.dbo.MyTable

+0

Come posso creare l'identificatore di 3 parti? esempio: dbname.dbo.tbldoc Voglio selezionare la colonna pgcount e la colonna creata da questa tabella da tutti i database. – Jeff

+0

Non si crea un identificatore di 3 parti, lo si usa semplicemente. Per collegarlo a ciò che hai, probabilmente dovresti usare qualche SQL dinamico. In effetti, potrebbe essere più semplice utilizzare sp_MSForEachDB: è sufficiente controllare l'output perché ho visto che in precedenza il proc escludeva alcuni database. – jlnorsworthy

+1

Questa risposta non risolve il problema. Il punto temporale è ottenere i nomi delle tabelle e non conoscere i nomi! Cosa succede se hai 300 tavoli? Dovresti duplicare questo comando 300 volte ??? –

2
CREATE TABLE #T 
(dbname sysname NOT NULL PRIMARY KEY, 
SumPGCOUNT INT, 
CREATED DATETIME) 

DECLARE @Script NVARCHAR(MAX) = '' 

SELECT @Script = @Script + ' 

USE ' + QUOTENAME(name) + ' 
IF EXISTS(SELECT * FROM sys.tables WHERE OBJECT_ID=OBJECT_ID(''dbo.tbldoc'')) 
    INSERT INTO #T 
    SELECT db_name() AS dbname, SUM(PGCOUNT) AS SumPGCOUNT, CREATED 
    FROM dbo.tbldoc 
    GROUP BY CREATED; 
    ' 
FROM sys.databases 
WHERE state=0 AND user_access=0 and has_dbaccess(name) = 1 
AND [name] like 'z%' and create_date between '2010-10-17' and '2011-01-15' 
ORDER BY [name] 

IF (@@ROWCOUNT > 0) 
BEGIN 
--PRINT @Script 
EXEC (@Script) 
SELECT * FROM #T 
END 

DROP TABLE #T 
+0

Viene visualizzato questo errore quando si esegue lo script: Messaggio 8120, livello 16, stato 1, riga 4 Colonna 'dbo.tbldoc.Creato 'non è valido nell'elenco di selezione perché non è contenuto in una funzione di aggregazione o nella clausola GROUP BY. – Jeff

+0

Ah, ho appena incollato la query originale. Immagino che tu abbia bisogno di un 'GROUP BY' lì dentro. –

+0

quando faccio il gruppo per creato, afferma che la colonna non esiste. la colonna è una colonna della tabella tbldoc. – Jeff

1

Il mio codice per la ricerca di dati provenienti da più di un database potrebbe essere:

use [master] 

go 

if object_id('tempdb.dbo.#database') is not null 

    drop TABLE #database 

go 

create TABLE #database(id INT identity primary key, name sysname) 

go 

set nocount on 

insert into #database(name) 

select name 

from sys.databases 

where name like '%tgsdb%' --CHANGE HERE THE FILTERING RULE FOR YOUR DATABASES! 

and source_database_id is null 

order by name 

Select * 
from #database 

declare @id INT, @cnt INT, @sql NVARCHAR(max), @currentDb sysname; 

select @id = 1, @cnt = max(id) 
from #database 

while @id <= @cnt 

BEGIN 

     select @currentDb = name 
    from #database 
    where id = @id 

    set @sql = 'select Column1, Column2 from ' + @currentDb + '.dbo.Table1' 
    print @sql 
    exec (@sql); 
    print '--------------------------------------------------------------------------' 
    set @id = @id + 1; 

END 

go 
+0

Funziona perfettamente per me. Grazie per aver condiviso questo! – AaBa

0

ho finito per scrivere una la settimana scorsa al volo per alcune cose che stavo facendo.

Blog post qui:

http://tsells.wordpress.com/2012/02/14/sql-server-database-iterator/

Ecco il codice.

SET NOCOUNT ON 
GO 
use master 
go 

Declare 
@dbname nvarchar(500), 
@variable1 int, 
@variable2 int, 
@variable3 int, 
@totaldb int = 0, 
@totaldbonserver int = 0, 
@totaldbwithmatches int = 0 

-- Get non system databases 
Declare mycursor CURSOR for select name, database_id from SYS.databases where database_id > 4 order by name desc 

open mycursor 

fetch next from mycursor into @dbname, @variable1 

while (@@FETCH_STATUS <> -1) 
    BEGIN 
     DECLARE @ParmDefinition NVARCHAR(500) 
     Declare @mysql nvarchar(500) = 'select @variable2OUT = COUNT(*) from [' + @dbname + '].INFORMATION_SCHEMA.TABLES where Upper(TABLE_NAME) like ''MyTable'''; 
     SET @ParmDefinition = N'@variable2OUT int OUTPUT' 
     set @totaldbonserver = @totaldbonserver + 1 
     Execute sp_executesql @mysql, @ParmDefinition, @variable2 OUTPUT    

     if @variable2 = 1 
     BEGIN 
      DECLARE @ParmDefinition2 NVARCHAR(500) 
      Declare @mysql2 nvarchar(500) = 'select @variable2OUT = COUNT(*) from [' + @dbname + '].dbo.MyTable'; 
      SET @ParmDefinition2 = N'@variable2OUT int OUTPUT' 
      Execute sp_executesql @mysql2, @ParmDefinition2, @variable3 OUTPUT 
      set @totaldb = @totaldb + 1 

      if @variable3 > 1 
      BEGIN 
       Print @dbname + ' matched the criteria' 
       set @totaldbwithmatches = @totaldbwithmatches + 1 
      END 
      ELSE 
      Select 1 
     END  

     fetch next from mycursor into @dbname, @variable1 
    END 
    PRINT 'Total databases on server: ' 
    Print @totaldbonserver 

    PRINT 'Total databases tested() : ' 
    Print @totaldb 

    PRINT 'Total databases with matches: ' 
    Print @totaldbwithmatches 
CLOSE mycursor 
DEALLOCATE mycursor 
1
DECLARE @Loop int 
DECLARE @MaxLoop int 
DECLARE @DBName varchar(300) 
DECLARE @SQL varchar(max) 

SET @Loop = 1 
SET @DBName = '' 

set nocount on 
SET @MaxLoop = (select count([name]) FROM sys.databases where [name] like 'Z%') 
WHILE @Loop <= @MaxLoop 
    BEGIN 
     SET @DBName = (select TableWithRowsNumbers.name from (select ROW_NUMBER() OVER (ORDER by [name]) as Row,[name] FROM sys.databases where [name] like 'Z%') TableWithRowsNumbers where Row = @Loop) 
     SET @SQL = 'USE [' + @DBName + ']' 
     exec (@SQL) 
     ... 
     ... 
     set @Loop = @Loop + 1 
    END 

*** Nota: non ho aggiunto il controllo se esiste qui.

0

Questo non utilizza un ciclo. Spero che questo ti aiuti!

Nota che "TABLE_OWNER" è uguale a "Proprietario SCHEMA" e "TABLE_TYPE" identificherà se l'elemento è una tabella O vista.

--This will return all tables, table owners and table types for all database(s) that are NOT 'Offline' 
--Offline database information will not appear 

Declare @temp_table table(
DB_NAME varchar(max), 
TABLE_OWNER varchar(max), 
TABLE_NAME varchar(max), 
TABLE_TYPE varchar(max), 
REMARKS varchar(max) 
) 

INSERT INTO @temp_table (DB_NAME, TABLE_OWNER, TABLE_NAME, TABLE_TYPE,REMARKS) 

EXECUTE master.sys.sp_MSforeachdb 'USE [?]; EXEC sp_tables' 

SELECT DB_NAME, TABLE_OWNER, TABLE_NAME, TABLE_TYPE 
FROM @temp_table 
--Uncomment below if you are seaching for 1 database 
--WHERE DB_NAME = '<Enter specific DB Name>' 

--For all databases other than 'System Databases' 
WHERE DB_NAME not in ('master','model','msdn','tempdb') 
order by 1,2,3