这似乎是一个有趣的挑战,并且目前已经击败了我,但如果其他人想尝试更进一步,我已经走了很远。
下面的脚本接受一个表名列表(如果需要,您可以轻松地将其扩展为包括 schema 和 db)并构建所有表中所有列的列表。然后它在pivots 上创建一个union all 脚本。
最终脚本目前分为三个部分,可以更优雅地组合在一起,其中还包括必须手动删除的 pivot 中的尾随 union all。第一部分是一个select null,用于包含每个列名,只是为了在最终输出中正确获取列标题。
这显然依赖于在所有具有相同名称的列中具有相同数据类型的所有表组合在一起,尽管即使输出的查询需要进一步的工作,它也应该尽量减少获得最终脚本所需的输入量.
查询
-- Create some dummy tables and data
create table a (a int, b int, c int, d nvarchar(500));
create table b (a int, c int, e int, f decimal(10,2));
insert into a values(1,1,1,'a');
insert into b values(2,2,2,2);
-- Create global temp tables to hold data required in the execute statement later
if object_id('tempdb..##SourceColumns') is not null
drop table ##SourceColumns;
if object_id('tempdb..##TargetColumns') is not null
drop table ##TargetColumns;
-- Find all columns in all the tables required
select t.name as TableName
,c.name as ColumnName
,ty.name as ColumnType
into ##SourceColumns
from sys.tables t
inner join sys.columns c
on(t.object_id = c.object_id)
inner join sys.types ty
on(c.system_type_id = ty.system_type_id)
where t.name in('a','b') -- Add list of tables here
order by t.name
,c.column_id;
DECLARE @ColsDummy AS NVARCHAR(MAX)
,@Cols AS NVARCHAR(MAX)
,@Query AS NVARCHAR(MAX);
-- This is to build the start of your UNION ALL query, so that you can specify "NULL as <column name>"
set @ColsDummy = STUFF((
SELECT distinct ',null as ' + QUOTENAME(ColumnName)
FROM ##SourceColumns
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
-- This is the list of column names to be used in the dynamically created PIVOT below
SET @Cols = STUFF((
SELECT distinct ', '','' as comma, ' + QUOTENAME(ColumnName)
FROM ##SourceColumns
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,16,'');
-- First part of final script
select 'select * from (select ''y'' as ignore, ' + @ColsDummy + ' union all';
-- Build and execute dynamic PIVOT for main part of UNION ALL query
set @Query = 'select ''select ''''n'''' as ignore,'' as [select], ' + @Cols + ', ''from '' + TableName + '' union all'' as [from]
from
(
select TableName
,ColumnName
from ##SourceColumns
) x
pivot
(
max(ColumnName)
for ColumnName in (' + replace(@Cols,', '','' as comma','') + ')
) p
'
execute(@Query);
-- Last part of final script
select ') a where ignore = ''n''' as [where];
-- Clean up global temp tables
if object_id('tempdb..##SourceColumns') is not null
drop table ##SourceColumns;
if object_id('tempdb..##TargetColumns') is not null
drop table ##TargetColumns;
输出
删除尾随 union all 并复制出三个 SSMS 结果窗口:
select * from (select 'y' as ignore, null as [a],null as [b],null as [c],null as [d],null as [e],null as [f] union all
select 'n' as ignore, a , b , c , d , NULL , NULL from a union all
select 'n' as ignore, a , NULL , c , NULL , e , f from b --<union all was here>
) a where ignore = 'n'
输出查询结果
|ignore| a | b | c | d | e | f |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| n | 1 | 1 | 1 | a | NULL| NULL|
| n | 2 | NULL| 2 | NULL| 2 | 2.00|