多个sp_MSforeachdb结果集的联合

时间:2014-02-05 13:05:10

标签: sql sql-server tsql

我可以成功查询多个数据库中的同一个表,如下所示:

DECLARE @command varchar(1000)
SELECT @command = 'select * from table'
EXEC sp_MSforeachdb @command

但是,正如预期的那样,所有这些结果都会在不同的结果窗口中返回。执行所有这些结果的最简单方法是什么?

3 个答案:

答案 0 :(得分:3)

请停止使用sp_MSforeachdb。为了任何东西。认真。它没有文档记载,没有支持,而且非常破碎:

如果你知道所有数据库都有相同的表(并且它们都具有相同的结构!),你可以这样做:

DECLARE @sql NVARCHAR(MAX);

SET @sql = N'';

SELECT @sql = @sql + N'UNION ALL SELECT col1,col2 /*, etc. */
  FROM ' + QUOTENAME(name) + '.dbo.tablename'
FROM sys.databases WHERE database_id > 4 AND state = 0;

SET @sql = STUFF(@sql, 1, 10, '');

EXEC sp_executesql @sql;

这会忽略系统数据库,不会尝试访问当前不是ONLINE的任何数据库。

现在,您可能希望进一步过滤,例如不包括任何没有名为tablename的表的数据库。在这种情况下,您需要嵌套动态SQL,例如:

DECLARE @sql NVARCHAR(MAX);

SET @sql = N'DECLARE @cmd NVARCHAR(MAX);

SET @cmd = N'''';';

SELECT @sql = @sql + N'

SELECT @cmd = @cmd + N''UNION ALL
SELECT col1,col2 /*, etc. */ FROM ' 
  + QUOTENAME(name) + '.dbo.tablename ''
WHERE EXISTS (SELECT 1 FROM ' + QUOTENAME(name) 
 + '.sys.tables AS t
 INNER JOIN ' + QUOTENAME(name) + '.sys.schemas AS s
 ON t.[schema_id] = s.[schema_id]
 WHERE t.name = N''tablename''
 AND s.name = N''dbo'');'
FROM sys.databases WHERE database_id > 4 AND state = 0;

SET @sql = @sql + N';

SET @cmd = STUFF(@cmd, 1, 10, '''');

PRINT @cmd;
--EXEC sp_executesql @cmd;';

PRINT @sql;
EXEC sp_executesql @sql;

这不会验证列结构是否兼容,但你很快就会发现它。

答案 1 :(得分:2)

另一种方法是使用动态SQL:

DECLARE @sql varchar(max);

SELECT @sql = Coalesce(@sql + ' UNION ALL ', '') + 'SELECT list, of, columns FROM ' + QuoteName(name) + '.schema.table'
FROM   sys.databases
;

PRINT @sql
--EXEC (@sql);

答案 2 :(得分:0)

存在一些整理问题,必须使用

AND COLLATION_NAME = 'SQL_Latin1_General_CP1_CI_AS'