【问题标题】:Script -> Query for multiple databases脚本 -> 查询多个数据库
【发布时间】:2020-02-25 21:47:38
【问题描述】:

我有以下问题:我想在我的 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)

如何使第一个示例工作?

【问题讨论】:

  • 根据数量和您的特定需求,您可以创建一个本地注册组,将每个客户数据库的注册添加到该组中,右键单击该组选择新查询。结果窗口将在所有数据库上执行您的查询,提供单个结果集以及源注册名称。

标签: sql sql-server database tsql


【解决方案1】:

这是不可能的,因为 sp_executesql 是作为它自己的独立批处理执行的,这意味着您确实“使用”了其他数据库,但仅限于我之前提到的那些批处理

我会尽量说清楚,你的这段代码是一个batch,因为里面没有“GO”命令(阅读我的sql cmets):

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 

【讨论】:

  • 好吧,现在我明白为什么我没有工作了。非常感谢您的帮助!!
  • 再问一个问题。在我的示例中,您将如何执行此操作:'select description from dbo.basicdata where description = 'xyz'' 我遇到了引号问题。
  • 你需要复制报价:set @dothis = 'select * from x where a = ''bcx'' '
  • @need_an_answer 如果您对我的回答满意,您介意将其标记为回答吗?谢谢
  • sry,我是新来的,不知道怎么做。我想,我现在就做到了:)。
【解决方案2】:

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

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

如您所见,我能够对多个数据库运行查询。如果我愿意,我什至可以将数据合并在一起。

【讨论】:

    【解决方案3】:

    虽然已经回答了为同一问题寻找解决方案,但我还是写了这个查询。 它提供数据并显示提供答案的数据库的来源。 请注意 order by 仅显示双精度值但会减慢结果

    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
    

    【讨论】:

      猜你喜欢
      • 2013-06-23
      • 1970-01-01
      • 2017-03-16
      • 2016-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多