我可以成功查询多个数据库中的同一个表,如下所示:
DECLARE @command varchar(1000)
SELECT @command = 'select * from table'
EXEC sp_MSforeachdb @command
但是,正如预期的那样,所有这些结果都会在不同的结果窗口中返回。执行所有这些结果的最简单方法是什么?
答案 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'