合并两个列数不同的表格

164

我有两个表(表A和表B)。

它们具有不同数量的列-比如说,表A有更多的列。

如何将这两个表联合起来,并且对于表B没有的列返回null值?


1
@LukasEder 请发布这个很棒的回答,它太好了,不在这里呈现就太可惜了 :) - Lukasz Szozda
@LukaszSzozda MySQL仍然不支持全连接。 - Ergest Basha
5个回答

313

对于列较少的表格,可以添加额外的空列,如下所示:

Select Col1, Col2, Col3, Col4, Col5 from Table1
Union
Select Col1, Col2, Col3, Null as Col4, Null as Col5 from Table2

7
有没有办法为 Null 列填充默认值? - Hans
4
你可以使用类似 isnull(ColumnName, 0) as ColumnName 或者 isnull(ColumnName, '-') as ColumnName 的方法。 - Kangkan
13
我发现这个解决方案也可以不列出所有列就能工作。所以,不必使用 Select Col1, Col2, Col3, Null as Col4, Null as Col5 from Table2 这样的语句,我们也可以使用 Select *, Null as Col4, Null as Col5 from Table2。请注意,这两个语句的意思是相同的。 - Pratik Patel
14
任何有效的提示——比如说你想要将一个有200列的表格与一个有2列的表格合并? - neydroydrec
2
@PratikPatel,您的解决方案仅适用于缺失列是最后一列的情况。您不能用SELECT *, Null as Col3, Null as Col4替换SELECT Col1,Col2,Null as Col3,Null as Col4,Col5 - Aidin
显示剩余6条评论

10

我来到这里并按照上面的答案进行操作。但是由于数据类型的顺序不匹配,导致出现错误。下面来自另一个答案的描述将会很有帮助。

你的结果是否与表中列的顺序相同?因为Oracle在列顺序方面非常严格。下面的示例会产生错误:

create table test1_1790 (
col_a varchar2(30),
col_b number,
col_c date);

create table test2_1790 (
col_a varchar2(30),
col_c date,
col_b number);

select * from test1_1790
union all
select * from test2_1790;

ORA-01790: 表达式必须与相应表达式具有相同的数据类型

正如您所看到的,错误的根本原因在于使用“*”作为列列表指定符所暗示的列顺序不匹配。通过显式输入列列表,可以轻松避免此类错误:

select col_a, col_b, col_c from test1_1790 union all select col_a, col_b, col_c from test2_1790; 更常见的错误情况是在SELECT列表中不小心交换(或移动)两个或多个列:

select col_a, col_b, col_c from test1_1790
union all
select col_a, col_c, col_b from test2_1790;

如果上述方法无法解决您的问题,那么可以考虑在列中创建别名,如下所示:(查询与您的查询不同,但这里的重点是如何在列中添加别名。)

SELECT id_table_a, 
       desc_table_a, 
       table_b.id_user as iUserID, 
       table_c.field as iField
UNION
SELECT id_table_a, 
       desc_table_a, 
       table_c.id_user as iUserID, 
       table_c.field as iField

我不得不使用相同的东西,但对于非空列,我添加了a.col_name和b.col_name。对于空列,我必须使用:NULL AS col_name1,NULL AS col_name2等。 - Scott R
1
注意:SELECT * UNION 可以多次链接;注意:WHERE 过滤器可以在每个 SELECT 子句中使用。 - mirekphd

5

通常情况下,当你使用基于集合的运算符时,需要拥有相同数量的列,所以Kangkan's answer是正确的。

SAS SQL有特定的运算符来处理这种情况:

SAS(R) 9.3 SQL Procedure User's Guide

CORRESPONDING (CORR) 关键字

只有在指定了集合运算符时才使用CORRESPONDING关键字。CORR使PROC SQL通过名称而不是序号来匹配表达式中的列。名称不匹配的列将被排除在结果表之外,但对于OUTER UNION运算符除外。

SELECT * FROM tabA
OUTER UNION CORR
SELECT * FROM tabB;

对于:

+---+---+
| a | b |
+---+---+
| 1 | X |
| 2 | Y |
+---+---+

OUTER UNION CORR

+---+---+
| b | d |
+---+---+
| U | 1 |
+---+---+

<=>

+----+----+---+
| a  | b  | d |
+----+----+---+
|  1 | X  |   |
|  2 | Y  |   |
|    | U  | 1 |
+----+----+---+

U-SQL支持类似的概念:

按名称在(*)上进行外部联合

OUTER

需要BY NAME子句和ON列表。与其他集合表达式相反,OUTER UNION的输出模式包括来自两侧的匹配列和非匹配列。这会创建一种情况,即来自其中一侧的每行都有“缺失列”,这些列仅存在于另一侧。对于这样的列,“缺失单元格”提供默认值。对于可空类型,缺省值为null,对于不可空类型(例如int),缺省值为.Net默认值0。

BY NAME

与OUTER一起使用时需要BY NAME子句。该子句指示联合是根据列名而不是位置匹配值。如果未指定BY NAME子句,则匹配将按位置进行。

如果ON子句包括“*”符号(可以指定为列表的最后一个或唯一成员),则允许超出ON子句中的额外名称匹配,并且结果的列按它们在左参数中出现的顺序包括所有匹配列。

代码如下:

@result =    
    SELECT * FROM @left
    OUTER UNION BY NAME ON (*) 
    SELECT * FROM @right;

编辑:

KQL支持外部联合的概念:

类型:

内部 - 结果具有所有输入表共同的子集列。

外部 - 结果具有出现在任何输入中的所有列。未由输入行定义的单元格设置为null。

示例:

let t1 = datatable(col1:long, col2:string)  
[1, "a",  
2, "b",
3, "c"];
let t2 = datatable(col3:long)
[1,3];
t1 | union kind=outer t2;

输出:

+------+------+------+
| col1 | col2 | col3 |
+------+------+------+
|    1 | a    |      |
|    2 | b    |      |
|    3 | c    |      |
|      |      |    1 |
|      |      |    3 |
+------+------+------+

DuckDB - 按名称 UNION (ALL)

The UNION (ALL) BY NAME clause can be used to combine rows from different tables by name, instead of by position. UNION BY NAME does not require both queries to have the same number of columns. Any columns that are only found in one of the queries are filled with NULL values for the other query.

SELECT * FROM capitals UNION BY NAME SELECT * FROM weather;


┌───────────┬─────────┬─────────┬────────────┐
│   city    │ country │ degrees │    date    │
│  varcharvarchar │  int32  │    date    │
├───────────┼─────────┼─────────┼────────────┤
│ Amsterdam │ NULL102022-10-14 │
│ Seattle   │ NULL82022-10-12 │
│ Amsterdam │ NL      │    NULLNULL       │
│ Berlin    │ Germany │    NULLNULL       │
└───────────┴─────────┴─────────┴────────────┘

1
有没有想过如何在SQL中实现这个? - Ketan Vaghasiya
据我所知,只有 SAS SQL 和 U-SQL 支持这个概念。 - Lukasz Szozda

1
在PostgreSQL中有一个选项叫做NATURAL FULL JOIN。你可以这样做:
SELECT *
FROM
    (SELECT *, 't1' AS source FROM t1) AS t1
NATURAL FULL JOIN
    (SELECT *, 't2' AS source FROM t2) AS t2
;

根据@lukasz-szozda在对原帖问题的评论中提到,参考这个答案

-1

如果只有一行,你可以使用join

Select t1.Col1, t1.Col2, t1.Col3, t2.Col4, t2.Col5 from Table1 t1 join Table2 t2;

两个1行表的联合(每个包含一个元组的多重集关系)将在结果关系中具有两行(元组)。在关系代数中(SQL不是),联合结果可能是一行,但仅当两个输入关系包含相同的元组时,例如一个单元组关系的自联接。 - Robert Monfera

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接