2011-01-18 15 views
6

Me preguntaba si alguien podría ayudarme a crear un ciclo while para iterar a través de varias bases de datos para obtener datos de una tabla de dos columnas. esto es lo he hecho hasta ahora. nada funciona porque no sé cómo hacer que el trabajo de selección comunicado a través de cada base de datos con respecto a la mesa que estoy interrogación por cada base de datos (dbo.tbldoc)While Loop para iterar a través de bases de datos

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 

Respuesta

27

yo consideraría sp_MSForEachDB que es mucho más fácil ...

Editar:

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


END 
' 
+0

¿Esto no trae todas las bases de datos? Solo estoy consultando bases de datos que comienzan con 'Z' – Jeff

+0

Sí, lo es, pero debe insertar los datos como resultado el código superior en una tabla y luego el filtro por nombre de db. – Marian

+0

¿cómo funciona este procedimiento? – Jeff

-1

Usted no tiene que utilizar un "uSO dE BASE dE DATOS" comunicado. Puede seleccionar de la tabla de base de datos en particular mediante el uso de un identificador de 3 partes como en:

seleccionar * de MyDatabase.dbo.MyTable

+0

¿cómo puedo crear el identificador de 3 partes? ejemplo: dbname.dbo.tbldoc Quiero seleccionar la columna pgcount y la columna creada desde esta tabla desde todas las bases de datos. – Jeff

+0

No crea un identificador de 3 partes, solo lo usa. Para enchufarlo a lo que tienes, probablemente deberías usar algunos sql dinámicos. De hecho, puede ser más fácil usar sp_MSForEachDB, simplemente verifique su resultado porque he visto que proc excluye algunas bases de datos anteriormente. – jlnorsworthy

+1

Esta respuesta no resuelve el problema. ¡El momento es obtener los nombres de la tabla y no saber los nombres! ¿Qué pasa si tienes 300 tablas? ¿Deberías duplicar este comando 300 veces? –

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

Recibo este error cuando ejecuto el script: Msg 8120, nivel 16, estado 1, línea 4 Columna 'dbo.tbldoc.Creado 'no es válido en la lista de selección porque no está contenido ni en una función de agregado ni en la cláusula GROUP BY. – Jeff

+0

Ah Acabo de pegar en su consulta original. Supongo que necesitas un 'GROUP BY' allí entonces. –

+0

cuando hago un grupo por creado, indica que la columna no existe. la columna es una columna de la tabla tbldoc. – Jeff

1

Mi código para buscar datos de más de una base de datos sería:

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

Esto funciona perfectamente bien para mí. ¡Gracias por compartir esto! – AaBa

0

Terminé escribiendo una última semana sobre la marcha de algunas cosas que estaba haciendo.

Blog post aquí:

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

Aquí está el código.

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: No añadí la comprobación de si existe aquí.

0

Esto no utiliza un bucle. ¡Espero que esto ayude!

Tenga en cuenta que "TABLE_OWNER" es lo mismo que "SCHEMA Owner" y "TABLE_TYPE" identificará si el elemento es una tabla OR view.

--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