在多个数据库上选择相同查询并将它们联合的规范方法是啥?
Posted
技术标签:
【中文标题】在多个数据库上选择相同查询并将它们联合的规范方法是啥?【英文标题】:What is the canonical way to select same query over multiple db's and union them?在多个数据库上选择相同查询并将它们联合的规范方法是什么? 【发布时间】:2016-12-20 10:10:39 【问题描述】:我的 SQL Server 设置中有 9 个数据库。我们称它们为 ONE_DB、TWO_DB 等。我发现自己正在做的一个非常常见的任务是从所有九个实例(通常是像 config 等非常小的表)中提取一些数据,对同一个表进行相同的查询,但对所有数据库进行查询。我会喜欢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 语句中进行更多处理,例如不同的连接、聚合、案例子句等,但我想你明白了。
这个过程还算可以,但是当select语句比较复杂的时候,代码就不是很容易阅读了。新人阅读这段代码也很困难,因为语法高亮器会将所有有趣的东西(select 语句)解释为字符串。
解决这个问题的“好”方法是什么?
【问题讨论】:
您能create a multi-database view 为您要对其执行这些操作的每个表吗? 如果您有一个相同的表,其中包含跨多个数据库的不同数据,您可能会遇到设计问题。是这样吗? 是否在同一台服务器上?如果是,则用于 eachdb 并过滤数据库名称。 @Nick.McDermaid 我不会称之为设计问题。不同客户有多个“相同”数据库实例,您可以说... 您可以动态构建(并执行)单个UNION ALL
查询,该查询会在 SSMS 的一个网格中为您输出结果。如select column from DB1.dbo.Table1 UNION ALL select column from DB2.dbo.Table1
【参考方案1】:
考虑使用 SQL Server Management Studio 的服务器组功能对多个服务器(或在您的情况下为同一服务器上的多个数据库)执行临时查询并自动合并结果。这可以按如下方式完成。
1) 右键单击 SSMS 对象资源管理器中的 Local Server Groups 节点,选择 New Server Group,并为其命名(例如 DevServerDatabases)。
2)在新组名上右击,选择New Server Registration,指定:
服务器名称=服务器名称 注册的服务器名称=数据库名称 数据库名称(连接属性选项卡)= 数据库名称 对每个数据库重复第 2 步将所有数据库添加到组后,右键单击组名并选择新建查询。在窗口中输入即席查询并执行。结果集将包含所有查询结果的并集加上数据库名称(Server Name
列),可以开启或关闭((Tools-->Options-->Query Results-->SQL Server-->多服务器结果)。
【讨论】:
这对于我的用例来说非常接近理想!易于添加/更改/共享临时查询,并且非常容易更新和更改设置。 SQL 也没有新的魔法——考虑到我同事的 SQL 能力水平,这很好!【参考方案2】:借助 Parse/Spit 函数并使用“token”作为数据库名称
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是
;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
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
;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',' ')
【讨论】:
这个解决方案很好,因为它在数据库数量等方面更通用。不过,它需要比@Dan 的解决方案更多的SQL 知识。如果我可以设置两个不同的答案作为解决方案,我也会标记这个! :) @LudvigH 当然,您将从两者中实现价值。这就是为什么我如此爱。就个人而言,我每天都学到一些东西……那是有趣的部分。干杯。【参考方案3】:使用 SSIS 从多个数据库中提取数据。在 SSIS 中,您可以合并或以其他方式转换数据并将其输出到 Excel。您还可以安排 SSIS 自动运行。
【讨论】:
以上是关于在多个数据库上选择相同查询并将它们联合的规范方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
在一列上选择 DISTINCT,返回多个其他列(SQL Server)
在一列上选择 DISTINCT,返回多个其他列(SQL Server)