版权声明:本文为CSDN博主「詩和遠方」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/helloword4217/article/details/103895643

SQL的开发者都知道Full Join(同Full Outer Join)是左右两个表的记录都取,但若多个表之间Full Join,较容易出现意料之外的结果,数据可能会重复,这里做一下简单介绍。

数据准备

  1. CREATE TABLE TA(ID INT,Attr NVARCHAR(100));
  2. CREATE TABLE TB(ID INT,Attr NVARCHAR(100));
  3. CREATE TABLE TC(ID INT,Attr NVARCHAR(100));
  4. INSERT INTO TA VALUES(1,'a'),(2,'b'),(3,'c'),(4,NULL),(5,'e');
  5. INSERT INTO TB VALUES(2,'aa'),(3,'bb'),(4,'cc'),(8,NULL);
  6. INSERT INTO TC VALUES(4,'aaa'),(5,'bbb'),(6,'ccc'),(8,'ddd');

需求

将TA、TB、TC三个表数据集中到一个结果集,若ID值重复,Attr字段依次从TA、TB、TC中取第一个非空值。

注:以上需求无法简单地用Union实现

SQL写法

错误写法

一般会像用 Inner Join 或 Left Join 一样,直接多次 Full Join

  1. SELECT
  2. COALESCE(a.ID, b.ID, c.ID) AS ID
  3. ,COALESCE(a.Attr, b.Attr, c.Attr) AS Attr
  4. FROM TA a
  5. FULL OUTER JOIN TB b ON a.ID = b.ID
  6. FULL OUTER JOIN TC c ON a.ID = c.ID

查询结果如下:
image.png
可以发现ID会有重复,所以这样写是不稳妥的,但为什么会错误呢,请看下图:
image.png
由于两个Full Join的条件都是与TA进行ID相等性连接,那么对TA中不存在且TB和TC都存在的ID,就会出现两条不同的记录。

正确写法

写法一:改进Join条件

  1. SELECT
  2. COALESCE(a.ID, b.ID, c.ID) AS ID
  3. ,COALESCE(a.Attr, b.Attr, c.Attr) AS Attr
  4. FROM TA a
  5. FULL OUTER JOIN TB b ON (a.ID = b.ID)
  6. FULL OUTER JOIN TC c ON (a.ID = c.ID OR b.ID = c.ID)

此方法在表非常多的时候条件会比较复杂,易出错

写法二:每次Join两个表,结果再与后面的表Join

  1. WITH cte_a AS
  2. (
  3. SELECT
  4. COALESCE(a.ID, b.ID) AS ID
  5. ,COALESCE(a.Attr, b.Attr) AS Attr
  6. FROM TA a
  7. FULL OUTER JOIN TB b ON a.ID = b.ID
  8. )
  9. SELECT
  10. COALESCE(a.ID, b.ID) AS ID
  11. ,COALESCE(a.Attr,b.Attr) AS Attr
  12. FROM cte_a AS a
  13. FULL OUTER JOIN TC b ON a.ID = b.ID

此方法在表非常多时,代码会比较冗长

写法三:构造全量ID,转换为Left Join

  1. WITH cte_a AS
  2. (
  3. SELECT ID FROM TA UNION
  4. SELECT ID FROM TB UNION
  5. SELECT ID FROM TC
  6. )
  7. SELECT
  8. COALESCE(b.ID, c.ID, d.ID) AS ID
  9. ,COALESCE(b.Attr, c.Attr, d.Attr) AS Attr
  10. FROM cte_a AS a
  11. LEFT JOIN TA b ON a.ID = b.ID
  12. LEFT JOIN TB c ON a.ID = c.ID
  13. LEFT JOIN TC d ON a.ID = d.ID

此方法使用Union去重,会存在Sort操作,必要时可以加上索引
————————————————
版权声明:本文为CSDN博主「詩和遠方」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/helloword4217/article/details/103895643链接