Reputation: 1192
I can successfully query the same table in multiple databases as follows:
DECLARE @command varchar(1000)
SELECT @command = 'select * from table'
EXEC sp_MSforeachdb @command
However, all of these results are, as expected, returned in different result windows. What's the easiest way to perform a union of all of these results?
Upvotes: 1
Views: 7180
Reputation: 280351
Please stop using sp_MSforeachdb
. For anything. Seriously. It's undocumented, unsupported, and spectacularly broken:
If you know that all databases have the same table (and that they all have the same structure!), you can do this:
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;
This ignores system databases and doesn't attempt to access any databases that are currently not ONLINE
.
Now, you may want to filter this further, e.g. not include any databases that don't have a table called tablename
. You'll need to nest dynamic SQL in this case, e.g.:
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;
This doesn't validate the column structure is compatible, but you'll find that out pretty quickly.
Upvotes: 9
Reputation: 104
Had some collation issues and had to use
AND COLLATION_NAME = 'SQL_Latin1_General_CP1_CI_AS'
Upvotes: 1
Reputation: 17161
Another way to skin this cat is to use dynamic 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);
Upvotes: 3