SQL - 联合两个表,每个表都有一些唯一的列

时间:2011-07-06 18:56:08

标签: sql sql-server tsql sql-server-2008

有两组患者记录数据(两个表),一组1999-2003,另一组2004-2009。每个都有> 100列; Table_A有~8个唯一列,Table_B~25个唯一列(相互比较)。我的目标是:

  1. 包含1999-2009所有数据的单一表格
  2. 对于一个表中不在另一个表中的行,只需为该列指定NULL值。例如如果表A具有Diagnostic_Category_12但Table_B没有,则该值将是表A中的原始值,但表B中为NULL
  3. 我见过一种手动执行此操作的方法: Unioning Two Tables With Different Number Of Columns

    但是,此数据集中的列太多,无法键入每个列 - 我只想自动创建列并根据需要插入NULL值。

    我正在使用SQL Server 2008R2。

5 个答案:

答案 0 :(得分:6)

更聪明地工作,而不是更努力。

我建议你通过查询你的模式来构建一些SQL ......这样你就不会错过任何手工编写的东西。您可以像这样生成脚本(只需用适当的表名替换@tableName1@tableName2值):

declare
 @tableName1 sysname = 'myfirsttablename'
,@tableName2 sysname = 'mysecondtablename'
,@select varchar(max) = 'select';

declare @columns table
(
     Id int identity(1,1)
    ,ColumName nvarchar(128)
    ,ExistsInTable1 bit
    ,ExistsInTable2 bit
);

-- Get a column listing with flags for their existence in each table
insert @columns
select distinct
 quotename(c.Column_Name)
,iif(c2.Table_Name is null, 0, 1)
,iif(c3.Table_Name is null, 0, 1)
from Information_Schema.Columns as c
    left join Information_Schema.Columns as c2
    on c2.Column_Name = c.Column_Name
    and c2.Table_Name = @tableName1
    left join Information_Schema.Columns as c3
    on c3.Column_Name = c.Column_Name
    and c3.Table_Name = @tableName2 
where c.Table_Name in (@tableName1, @tableName2);

-- Build the select statement for the 1sttable (using null where the column is absent)
select
 @select += char(10) + iif(c.Id = 1, ' ', ',') 
+ iif(c.ExistsInTable1 = 1, c.ColumName, 'null') + ' as ' + c.ColumName
from @columns as c
order by c.Id;

set @select += '
from ' + quotename(@tableName1) + '
union all
select';

-- Build the select statement for the 2ndtable (using null where the column is absent)
select
 @select += char(10) + iif(c.Id = 1, ' ', ',') 
+ iif(c.ExistsInTable2 = 1, c.ColumName, 'null') + ' as ' + c.ColumName
from @columns as c
order by c.Id;

set @select += '
from ' + quotename(@tableName2);

-- Print or execute your sql.
print(@select); -- or exec(@select);

生成SQL后,我建议您:

  1. 根据需要验证结果并调整查询。
  2. 将最终的SQL放在存储过程中,而不是为每个请求动态生成它。

答案 1 :(得分:5)

即使你认为

  

这里有太多的专栏   数据集在

中键入每个数据

这是正确的做法。任何其他解决方案基本上都是黑客攻击。

这很容易做到,我经常使用更宽的表格(150个字段)。

在SSMS中,右键单击两个表中较大的一个,Script Table As - > Select To - > New Query Editor Window。这将输出一个新窗口,其中列出了该表中每个字段的选择脚本,每个字段都在其自己的行上,因此很容易管理。

这实际上将是大约5分钟的工作。 第一次就做对了。

答案 2 :(得分:1)

快速而又脏的方法是将NULL列与其他表的唯一列的名称一起添加到每个表中。 E.g:

ALTER TABLE TableA ADD tableBUniqueColumn1 INT SPARSE NULL, tableBUniqueColumn2 INT SPARSE NULL, ...
ALTER TABLE TableB ADD tableAUniqueColumn1 INT SPARSE NULL, tableAUniqueColumn2 INT SPARSE NULL, ...

现在这些表将具有相同的架构,您可以轻松地对它们执行联合。

这是一个非常hacky的解决方法。包含SPARSE NULL列的表通常是一个警告标志,表示您不创建关系,而是尝试将所有数据放入一个表中。这通常是一个错误,会使维护数据变得更加困难。

如果您尝试规范化数据,从长远来看,创建新架构并使用现有数据填充新架构会更快,而不是破坏现有表。这可能看起来很多工作,但你只需要做一次。如果您决定采用hacky解决方法,那么您的工作将永远不会结束。

答案 3 :(得分:0)

您想要NULL值的任何地方,您仍需要在查询中提及它们。它可能会非常难看......

您是否可以将年份用作公共列,然后将LEFT OUTER JOIN其他两个表用于它?例如:

WITH Y AS (
  SELECT 1999 YearId UNION SELECT 2000 UNION SELECT 2001 -- and so on...
)
SELECT Y.YearId, Table_A.*, Table_B.*
FROM Y LEFT OUTER JOIN
     Table_A ON Y.YearId = Table_A.YearId LEFT OUTER JOIN
     Table_B ON Y.YearId = Table_B.YearId
;

答案 4 :(得分:0)

超过100列?不值得自动化。在这种情况下,我认为手动方法更快。 无论如何,有很多方法:

  1. 使用信息架构视图或目录视图访问列元数据以创建动态插入语句(union语句)
  2. 使用SMO(服务器管理对象)编写程序以将表合并到第三个表中
  3. 将两个表格导出到Excel,将它们合并在一起,然后将结果导入第三个表格。
  4. 以及其他一些方式。