在多个数据库上选择相同查询并将它们联合起来的规范方法是什么?

时间:2016-12-20 10:10:40

标签: sql-server tsql

我的SQL Server设置中有9个数据库。让我们称它们为ONE_DB,TWO_DB等。我发现自己正在做的一个非常常见的任务是从所有九个实例(通常是非常小的表,如配置等)中提取一些数据,对同一个表但在所有数据库中使用相同的查询。我想要一个union all select interesting_col from *.dbo.tableX

基于SO上的其他问题,我提出了一种方法来做到这一点,但我对此解决方案并不满意。可以说我只想要一个表中的一列,我首先运行下面的SQL查询...

declare @db varchar(30)
declare @db_list varchar(200)
set @db = ''
set @db_list = 'ONE_DB,TWO_DB,THREE_DB,FOUR_DB,FIVE_DB,SIX_DB,SEVEN_DB,EIGHT_DB,NINE_DB'

while len(@db_list) > 0
begin
  set @db = left(@db_list, charindex(',', @db_list+',')-1);
  set @db_list = stuff(@db_list, 1, charindex(',', @db_list+','), '');
  exec ( 'use '+@db+'; select tx.interesting_columns from dbo.TableX as tx;')
end

...然后我手动将9个结果集复制粘贴到Excel。当然我通常在select语句中做一些处理,比如不同的连接,聚合,case-clause等。但我想你明白了。

这个过程非常好,但是当有更复杂的select语句时,代码不是很容易阅读。由于语法highlighter将所有有趣的东西(select语句)解释为字符串,因此新人阅读此代码也很困难。

什么是"好"处理这个的方法?

3 个答案:

答案 0 :(得分:2)

借助Parse / Spit功能并使用“令牌”作为数据库名称

Declare @db_list varchar(max) = 'ONE_DB,TWO_DB,THREE_DB,FOUR_DB,FIVE_DB,SIX_DB,SEVEN_DB,EIGHT_DB,NINE_DB'
Declare @cmd     varchar(max) = ';Use <<dbname>>; select interesting_col from dbo.tableX'
Declare @SQL     varchar(max) = '>>>'

Select @SQL = Replace(Replace(@SQL+replace(@cmd,'<<dbname>>',QuoteName(RetVal))+char(13),'>>>Union All',''),'>>>','')
 From [dbo].[udf-Str-Parse](@db_list,',')

Exec(@SQL)
  

示例1

Declare @cmd     varchar(max) = ';Use <<dbname>>; select interesting_col 

SQL Generated是

;Use [ONE_DB];select interesting_col from *.dbo.tableX
;Use [TWO_DB];select interesting_col from *.dbo.tableX
;Use [THREE_DB];select interesting_col from *.dbo.tableX
;Use [FOUR_DB];select interesting_col from *.dbo.tableX
;Use [FIVE_DB];select interesting_col from *.dbo.tableX
;Use [SIX_DB];select interesting_col from *.dbo.tableX
;Use [SEVEN_DB];select interesting_col from *.dbo.tableX
;Use [EIGHT_DB];select interesting_col from *.dbo.tableX
;Use [NINE_DB];select interesting_col from *.dbo.tableX
  

示例2 - 合并结果

Declare @cmd     varchar(max) = 'Union All select DBName=''<<dbname>>'',interesting_col from <<dbname>>.dbo.tableX'

SQL Generated

 select DBName='[ONE_DB]',interesting_col from [ONE_DB].dbo.tableX
Union All select DBName='[TWO_DB]',interesting_col from [TWO_DB].dbo.tableX
Union All select DBName='[THREE_DB]',interesting_col from [THREE_DB].dbo.tableX
Union All select DBName='[FOUR_DB]',interesting_col from [FOUR_DB].dbo.tableX
Union All select DBName='[FIVE_DB]',interesting_col from [FIVE_DB].dbo.tableX
Union All select DBName='[SIX_DB]',interesting_col from [SIX_DB].dbo.tableX
Union All select DBName='[SEVEN_DB]',interesting_col from [SEVEN_DB].dbo.tableX
Union All select DBName='[EIGHT_DB]',interesting_col from [EIGHT_DB].dbo.tableX
Union All select DBName='[NINE_DB]',interesting_col from [NINE_DB].dbo.tableX
  

示例3 - 执行存储过程

Declare @cmd     varchar(max) = ';Use <<dbname>>; exec SomeStoredProcedure'

SQL Generated

;Use [ONE_DB]; exec SomeStoredProcedure
;Use [TWO_DB]; exec SomeStoredProcedure
;Use [THREE_DB]; exec SomeStoredProcedure
;Use [FOUR_DB]; exec SomeStoredProcedure
;Use [FIVE_DB]; exec SomeStoredProcedure
;Use [SIX_DB]; exec SomeStoredProcedure
;Use [SEVEN_DB]; exec SomeStoredProcedure
;Use [EIGHT_DB]; exec SomeStoredProcedure
;Use [NINE_DB]; exec SomeStoredProcedure
  

UDF(如果需要)

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (  
    Select RetSeq = Row_Number() over (Order By (Select null))
          ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
    From (Select x = Cast('<x>'+ Replace(@String,@Delimiter,'</x><x>')+'</x>' as xml).query('.')) as A 
    Cross Apply x.nodes('x') AS B(i)
);
--Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')

答案 1 :(得分:2)

考虑使用SQL Server Management Studio的服务器组功能对多个服务器(或您的案例中同一服务器上的多个数据库)执行即席查询,并自动联合结果。这可以按如下方式完成。

1)右键单击SSMS对象资源管理器中的“本地服务器组”节点,选择“新建服务器组”,并为其指定一个助记符名称(例如DevServerDatabases)。

2)右键单击新组名,选择New Server Registration,指定:

  • 服务器名称=服务器名称
  • 注册服务器名称=数据库名称
  • 数据库名称(连接属性选项卡)=数据库名称
  • 为每个数据库重复步骤2

将所有数据库添加到组后,右键单击组名称并选择“新建查询”。在窗口中输入临时查询并执行。结果集将包含所有查询结果的联合以及数据库名称(Server Name列),可以打开或关闭((工具 - &gt;选项 - &gt;查询结果 - &gt; SQL Server - &gt;多服务器结果)。

答案 2 :(得分:0)

使用SSIS从多个数据库中提取数据。在SSIS中,您可以合并并以其他方式转换数据并将其输出为excel。您还可以安排SSIS自动运行。