脚本 - >查询多个数据库

时间:2014-08-01 08:05:13

标签: sql sql-server database tsql

我有以下问题:我想在SQL Server上的多个数据库上执行查询。每个客户都有一个单独的数据库这些都有完全相同的表,他们的名字相似。所以有一个数据库kde_01_Miller,然后是kde_02_Mueller等等......

我想在每个数据库中执行查询。

以下是我的尝试:

DECLARE @name VARCHAR(100) -- database name
DECLARE @dothis nvarchar(200)

DECLARE db_cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
WHERE name like 'kde_0%'
order by name

OPEN db_cursor  
FETCH NEXT FROM db_cursor INTO @name  

WHILE @@FETCH_STATUS = 0
BEGIN  
       set @dothis = 'use [' + @name + ']'
       exec sp_executesql @dothis

       /* Start query */
       select description from dbo.basicdata
       /* End query */

       FETCH NEXT FROM db_cursor INTO @name  
END  

CLOSE db_cursor  
DEALLOCATE db_cursor

问题是查询无法正常运行。 use语句似乎不起作用。我得到了每个数据库的结果,但结果总是相同的,取决于我正在进行查询的数据库。

我也尝试过以下内容并且它有效:我没有使用while循环,而是执行了此操作:

WHILE @@FETCH_STATUS = 0
BEGIN  
       set @dothis= 'select description from ' + QUOTENAME(@name) + '.dbo.basicdata'
       exec sp_executesql @dothis

       FETCH NEXT FROM db_cursor INTO @name  
END 

但我不喜欢这种方式,因为每张桌子都需要quotename(@name)

如何让第一个示例正常工作?

3 个答案:

答案 0 :(得分:1)

这是不可能的,因为sp_executesql是作为自己独立的批次执行的,这意味着你实际上已经"使用"其他数据库,但仅限于我之前提到的那些批次

我会更加清楚,这段代码是批次,因为没有" GO &# 34;命令里面(读我的SQL注释):

DECLARE @name VARCHAR(100) -- database name
DECLARE @dothis nvarchar(200)

DECLARE db_cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
WHERE name like 'kde_0%'
order by name

OPEN db_cursor  
FETCH NEXT FROM db_cursor INTO @name  

WHILE @@FETCH_STATUS = 0
BEGIN  
       set @dothis = 'use [' + @name + ']'
       -- this will create another batch and execute the @dothis
       -- it'll have nothing todo with your current executing batch, 
       -- which is calling the sp_executesql
       exec sp_executesql @dothis 

       /* Start query */
       select description from dbo.basicdata
       /* End query */

       FETCH NEXT FROM db_cursor INTO @name  
END  

CLOSE db_cursor  
DEALLOCATE db_cursor

所以,只剩下一条路了,在@dothis中写下你想对数据库做的任何事情:

declare @dothis nvarchar(max)
set @dothis = '
use [' + @name + ']
-- query start
Select description from dbo.basicdata
-- query end 
'
exec sp_executesql @dothis 

答案 1 :(得分:0)

虽然这个问题已经得到解答,但我认为我提供的第二个答案我认为更好。您可以生成动态SQL来查询多个数据库,而不是使用Cursor。

DECLARE @sql NVARCHAR(Max);

SELECT @sql = COALESCE(@sql, '') + 'SELECT * FROM '  + [name] + '.sys.tables' + CHAR(13)
FROM sys.databases

PRINT @sql
EXEC sp_executesql @sql

上面的SQL将生成以下SQL。

SELECT * FROM master.sys.tables
SELECT * FROM tempdb.sys.tables
SELECT * FROM model.sys.tables
SELECT * FROM msdb.sys.tables
SELECT * FROM StackOverflow.sys.tables
SELECT * FROM AdventureWorks2012.sys.tables
SELECT * FROM AdventureWorksDW2012.sys.tables

如您所见,我能够针对多个数据库运行查询。如果我愿意,我甚至可以将数据联合起来。

答案 2 :(得分:0)

尽管在针对同一问题的解决方案中已经给出了答案,但我还是写了此查询。 它提供了数据,并显示了提供答案的数据库源。 请注意,排序依据仅是显示双精度值,但会减慢结果速度

declare @results table (
    name varchar(50),
       clientnr numeric(20) ,
       dbname_source varchar(20)

);

insert @results
exec sp_msforeachdb N'
use [?]

if left(''?'',3) = ''ons''        -- only execute the query against databases  that match the naming pattern in this example starting with ons  (use your own database names make sure to exclude systemdatabases


    --and ''?'' <> ''MIS_MTA''
begin

--select script  that to be executed over multiple databases

    select distinct
       c.name,
          c.identificationNo as numeric,
          d.table_catalog



    from [?].dbo.clients as c ,  [?].INFORMATION_SCHEMA.COLUMNS as d               
       where 1=1
       and isnumeric(c.identificationNo) = 1

end;
';

select * from @results
where
isnumeric(clientnr) = 1

order by 2
;

示例结果:

name    clientnr    dbname_source
TestclientA 9000    OnsDB
TestclientA 9000    OnsDB_Fixed
Storcken    9999    OnsDB_Fixed
Storcken    9999    OnsDB