【问题标题】:MySQL: Join with 4 tables and common field: row_number()MySQL:加入 4 个表和公共字段:row_number()
【发布时间】:2021-09-14 07:12:45
【问题描述】:

我有 4 张桌子 -

制表符:d

Name | ID 
----------
A    | 1
B    | 2
C    | 3

标签:p

Name | ID 
----------
AX   | 1
B    | 2
X    | 3
Y    | 4
Z    | 5

标签:s

Name | ID 
----------
A    | 1
BL   | 2
V    | 3
M    | 4

标签:a

Name | ID 
----------
K    | 1
J    | 2
H    | 3
N    | 4

现在我用的是 MySQL,今天发现 MySQL 不支持 FULL join。所以,我对所有 4 个表使用左连接,然后使用“联合”和右连接来合并所有 4 个表的记录。 我正在使用的查询就像 -

(select d.Name, p.Name, s.Name, a.Name from doc d 
left join
prof p
on d.id = p.id
left join
sing s
on d.id = s.id
left join
act a
on d.id = a.id)
union
(select d.Name, p.Name, s.Name, a.Name from doc d 
right join
prof p
on d.id = p.id
right join
sing s
on d.id = s.id
right join
act a
on d.id = a.id)

但这并没有给出预期的输出。它给出了类似的东西 -

D    |    P    |   S    |    A
---------------------------------
A    |    AX   |   A    |    K     
B    |    B    |   BL   |    J
C    |    X    |   V    |    H
NULL |    NULL |   NULL |    N

实际输出应该是-

D    |    P    |   S    |    A
---------------------------------
A    |    AX   |   A    |    K     
B    |    B    |   BL   |    J
C    |    X    |   V    |    H
NULL |    Y    |   M    |    N
NULL |    Z    |   NULL |    NULL

请帮我弄清楚我错过了什么!也帮助我得到结果...

【问题讨论】:

  • 只是一个关于如何使它更容易的线索:select * from d,p,s,a;
  • @FlashThunder No, never 如果可以避免的话,在 from 子句中添加逗号。
  • @TimBiegeleisen 为什么不呢,它比 join 快得多(在语法和计算时间上)
  • 什么是 MySQL 版本?

标签: mysql join


【解决方案1】:

您真正想要的行为是完全外连接,但 MySQL 不直接支持它(而且解决方法相当难看)。我可以在这里建议的一种方法是维护第五个表,其中包含您期望在结果集中出现的所有 ID 值。考虑:

SELECT c.ID, d.Name, p.Name, s.Name, a.Name
FROM
(SELECT 1 AS ID UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL
 SELECT 4 UNION ALL SELECT 5) c
LEFT JOIN d ON d.ID = c.ID
LEFT JOIN p ON p.ID = c.ID
LEFT JOIN s ON s.ID = c.ID
LEFT JOIN a ON a.ID = c.ID
ORDER BY c.ID;

【讨论】:

  • 谢谢蒂姆!但我想让查询稍微概括一下,而不是针对我在这里提到的示例。创建 ID 表(临时)和硬编码 5 个条目使查询更难实现。你能想出一些更通用的东西吗?
  • @AmitavaChowdhury 我不同意,我的回答是走这里的路。在 MySQL 中模拟 4 个表之间的完全外部联接的通用 解决方案将非常丑陋且难以维护代码。你应该得到第五个表来维护所有的 ID,然后加入到上面显示的各个表中。
  • 但是蒂姆!为此,我需要知道要在 ID 临时表中维护的最大 ID 数,并手动编写查询以从临时表中选择该 ID 数!我只是因为这个原因而担心......
  • @AmitavaChowdhury 对,这就是我建议使用这些 ID 维护 table 的方法。顺便说一句,这里需要做这样一个完整的外部连接表明数据库设计很差。您的系统中应该有 一个 包含所有 ID 的主表。在这些其他表中,ID 应该是外键。
【解决方案2】:

假设您使用的是 MySQL v8,您可能可以这样做:

WITH RECURSIVE cte AS (
SELECT 1 AS rn, MAX(cnt) AS mxcnt 
  FROM
  ( SELECT COUNT(ID) cnt FROM doc UNION 
    SELECT COUNT(ID) FROM prof UNION 
    SELECT COUNT(ID) FROM sing UNION 
    SELECT COUNT(ID) FROM act ) v UNION ALL
SELECT rn+1, mxcnt FROM cte WHERE rn+1 <= mxcnt)

SELECT c.rn, d.Name, p.Name, s.Name, a.Name
  FROM cte c 
  LEFT JOIN doc d ON d.ID = c.rn
  LEFT JOIN prof p ON p.ID = c.rn
  LEFT JOIN sing s ON s.ID = c.rn
  LEFT JOIN act a ON a.ID = c.rn
ORDER BY c.rn;

使用WITH RECURSIVE根据所有相关表的最大计数结果生成编号序列,然后将其用作LEFT JOIN中的引用。我同意 Tim 的观点,即为所有 id 建立一个主表。

【讨论】:

    猜你喜欢
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-31
    • 1970-01-01
    • 2015-04-02
    • 2020-07-26
    • 2018-10-20
    相关资源
    最近更新 更多