【问题标题】:How to correctly combine multiple WHERE statements and multiple ON clauses when emulating a FULL OUTER JOIN in MySQL在 MySQL 中模拟 FULL OUTER JOIN 时如何正确组合多个 WHERE 语句和多个 ON 子句
【发布时间】:2023-03-27 21:34:01
【问题描述】:

我有两张桌子。全球捕鱼数据(捕捞和水产养殖)。我想通过在 MySQL 中模拟 FULL OUTER JOIN 来组合。

Tbl_A - 捕获

  • capture_id
  • year_c
  • species_c
  • iso_code_c
  • area_code_c
  • environ_code_c
  • qty_taken
  • value_c
  • symbol_c

Tbl_B - 水产养殖

  • aqua_id
  • year_a
  • species_a
  • iso_code_a
  • area_code_a
  • environ_code_a
  • qty_prod
  • value_aqua
  • symbol_a

这很复杂:

  • Tbl_A 和 Tbl_B 不相关
  • Tbl_B 可能没有对应的行

Tbl_A - 捕获

cap_id| yr_c| sp_c| iso_c| area_c| qty_c
     3| 2015|  TRR|    54|      8|   120
   678| 2015|  BOM|    62|     27|   0.0
    20| 2015|  TRR|    54|     27|   0.0
    45| 2015|  FRC|     7|     15| 86800

Tbl_B - 水产养殖

cap_id| yr_a| sp_a| iso_a| area_a| qty_a
    78| 2015|  OTS|    32|     27|  6868
   333| 2015|  FRC|     7|     15|   550
   789| 2015|  TRR|    54|     27| 45000
   987| 2015|  TRR|    32|     27|    40

对于选定的年份(2015 年),我正在尝试捕捉:

  1. Tbl_A 和 Tbl_B 记录(物种、iso_code、区域)相同的地方;
  2. 没有 Tbl_B 匹配的 Tbl_A 记录(物种、iso_code、区域);和
  3. 没有 Tbl_A 匹配的 Tbl_B 记录(物种、iso_code、区域)。

Tbl_C - 所需的最终 Tbl

id| cap_id| aqua_id| yr_c| yr_a| sp_c| sp_a| iso_c| iso_a|area_c|area_a| qty_c| qty_a 

1 |     20|     789| 2015| 2015|  TRR|  TRR|    54|    54|    27|    27|   0.0| 45000
2 |     45|     333| 2015| 2015|  FRC|  FRC|     7|     7|    15|    15| 86800| 550
3 |    678|    NULL| 2015| NULL|  BOM| NULL|    62|  NULL|    27|  NULL|   0.0| NULL
4 |      3|    NULL| 2015| NULL|  TRR| NULL|    54|  NULL|     8|  NULL|   120| NULL
5 |   NULL|      78| NULL| 2015| NULL|  OTS|  NULL|    32|  NULL|    27|  NULL| 6868    
6 |   NULL|     987| NULL| 2015| NULL|  TRR|  NULL|    32|  NULL|    27|  NULL| 40

我有一个使用 UNION 来连接两个左连接的查询:

(SELECT 
c.capture_id,
a.aqua_id,
c.year_c,
a.year_a,
c.species_c,
a.species_a,
c.iso_code_c,
a.iso_code_a,
c.area_c,
a.area_a,
c.environ_code_c,
a.environ_code_a,
c.qty_taken,
a.qty_prod
FROM capture AS c 
LEFT JOIN aquaculture AS a 
ON c.year_c = a.year_a AND c.iso_code_c = a.iso_code_a AND c.area_c = a.area_a AND c.species_c = 
a.species_a
WHERE c.year_c = 2015 AND a.year_a = 2015)
UNION
(SELECT 
c.capture_id,
a.aqua_id,
c.year_c,
a.year_a,
c.species_c,
a.species_a,
c.iso_code_c,
a.iso_code_a,
c.area_c,
a.area_a,
c.qty_taken,
a.qty_prod
FROM  aquaculture AS a
LEFT JOIN capture AS c 
ON c.year_c = a.year_a AND c.iso_code_c = a.iso_code_a AND c.area_c = a.area_a AND c.species_c = a.species_a
WHERE a.year_a = 2015 AND c.year_c = 2015);

但上面的查询只返回一小部分匹配记录

id| cap_id| aqua_id| yr_c| yr_a| sp_c| sp_a| iso_c| iso_a|area_c|area_a| qty_c| qty_a 

1 |     20|     789| 2015| 2015|  TRR|  TRR|    54|    54|    27|    27|   0.0| 45000
2 |     45|     333| 2015| 2015|  FRC|  FRC|     7|     7|    15|    15| 86800|   550

我不明白我是如何取消 LEFT JOINS 的效果的

【问题讨论】:

标签: mysql constraints left-join full-outer-join


【解决方案1】:

由于 MySQL 仅支持左、右和内连接 - 您需要编写两个查询:1) 表 A 左连接表 B 2) 表 B 左连接表 A。然后在 @987654321 的帮助下将它们组合成一个结果@。 Union 还会删除结果中的重复行,因此结果集中只有 3 种类型的行:

  1. 包含两个表中数据的行,即 A 内连接 B
  2. 包含表 A 中的数据的行,其中没有来自 B 的匹配项。即 A 左连接 B
  3. 包含表 B 中的数据的行,其中 A 中没有匹配项,即 B 左连接 A

试试:

SELECT ...
FROM c
LEFT JOIN a ON ...
UNION
SELECT ...
FROM a
LEFT JOIN c ON ...

【讨论】:

  • 这不会在结果中创建第 10 行,它同时具有 c_ida_id。他真的想要一个完整的外部连接。
  • 糟糕,那行是错误的,它缺少一列。
  • 不确定是否是完全外连接?是的,第 10 行的错字(doh!)
  • 不确定是否是完全外连接?当我尝试完全连接时,最初查询运行但在 T2 中没有行匹配时停止。这就是我尝试左外连接的原因。因为即使 T2 完成也需要加载 T1 数据? c_id 和 a_id 可以在同一行。一张桌子是捕获的鱼,另一张是水产养殖(生产)。在年份、iso_code、面积和物种相同的地方,我需要它们在同一行中,这样我就可以对全球总量求和。但是,如果该年仅捕获或仅针对 iso_code、区域和物种的给定组合进行水产养殖生产,我也需要加载。
  • @maksym 谢谢,但 union all 垂直堆叠数据。我需要它是水平的。我认为 Barmar 是对的,因为它是我需要的加入。只是似乎无法正确获取查询的结构......
【解决方案2】:

您的问题出在WHERE 子句中。您正在排除“RIGHT”表记录为空的记录。

SELECT *
FROM c LEFT JOIN a ON ...
WHERE c.year = 2015 /*remove AND a.year = 2015*/
UNION SELECT *
FROM a LEFT JOIN c ON ...
WHERE a.year = 2015 /*remove AND c.year = 2015*/

【讨论】:

  • 这个答案没有解释为什么他们排除在外并且没有将其与代码联系起来。不清楚。
  • @zambonee 和 (@philpxy) 非常感谢。 WHERE 子句更改有效。我必须从捕获表中删除 42 个重复项,但鉴于 900,000 行 42 非常干净。
  • 我现在更好地理解了 2nd year = xxxx 如何产生与 INNER JOIN 相同的效果。尚不完全清楚第二个 LEFT JOIN 逻辑。明天继续工作。
猜你喜欢
  • 2021-09-23
  • 2020-03-09
  • 2015-08-10
  • 1970-01-01
  • 2021-09-29
  • 1970-01-01
  • 2014-05-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多