San*_*eep 4 mysql join mysql-5.6
我们可以使用以下简单示例重新创建一种情况。我有以下两个示例表:
CREATE TABLE contact_info
(
id INT UNSIGNED AUTO_INCREMENT,
priContactId INT,
secContactId INT,
blahBlah VARCHAR(32),
PRIMARY KEY(id)
);
Run Code Online (Sandbox Code Playgroud)
和
CREATE TABLE name_lookup
(
id INT UNSIGNED AUTO_INCREMENT,
contactID INT,
contactName VARCHAR(32),
PRIMARY KEY(id)
);
Run Code Online (Sandbox Code Playgroud)
我按如下方式填充它们:
INSERT INTO contact_info(priContactId, secContactId, blahBlah) VALUES(1, 3, "Team A"), (4, 2, "Team B");
INSERT INTO name_lookup(contactID, contactName) VALUES(1, "John Doe"), (2, "Mary Smith"), (3, "Jose Garcia"), (4, "Larry Brown");
Run Code Online (Sandbox Code Playgroud)
显然,表的内容如下:
+----+--------------+--------------+----------+
| id | priContactId | secContactId | blahBlah |
+----+--------------+--------------+----------+
| 1 | 1 | 3 | Team A |
| 2 | 4 | 2 | Team B |
+----+--------------+--------------+----------+
+----+-----------+-------------+
| id | contactID | contactName |
+----+-----------+-------------+
| 1 | 1 | John Doe |
| 2 | 2 | Mary Smith |
| 3 | 3 | Jose Garcia |
| 4 | 4 | Larry Brown |
+----+-----------+-------------+
Run Code Online (Sandbox Code Playgroud)
我们想执行一个 JOIN 操作,以便我们得到这样的输出:
+-------------+-------------+--------+
| John Doe | Jose Garcia | Team A |
+-------------+-------------+--------+
| Larry Brown | Mary Smith | Team B |
+-------------+-------------+--------+
Run Code Online (Sandbox Code Playgroud)
priContactId和secContactId列的连接约束是相同的,我很难弄清楚 JOIN 查询应该是什么样子。
仅供参考,我们使用的是 MySQL 版本5.6.49。
这是一个有趣的例子,SELF-JOIN证明了(间接)s 是有用的!
为了回答您的问题,我执行了以下操作(以下所有 SQL 都可以在此处的小提琴上找到):
我使用了问题中提供的 DDL 和 DML - 谢谢你(和 +1 - 你只问了两个问题,所以我认为你是一个新的贡献者,很高兴看到有些人不厌其烦地提供 DDL 和 DML - 如果所有 OP 都这样做!)。
CREATE TABLE name_lookup
(
id INT UNSIGNED AUTO_INCREMENT,
contact_id INT,
contact_name VARCHAR(32),
PRIMARY KEY(id)
);
CREATE TABLE contact_info
(
id INT UNSIGNED AUTO_INCREMENT,
pri_contact_id INT,
sec_contact_id INT,
blah_blah VARCHAR(32),
PRIMARY KEY(id)
);
Run Code Online (Sandbox Code Playgroud)
填充它们:
INSERT INTO name_lookup(contact_id, contact_name)
VALUES
(1, "John Doe"), (2, "Mary Smith"),
(3, "Jose Garcia"), (4, "Larry Brown");
Run Code Online (Sandbox Code Playgroud)
和
INSERT INTO contact_info(pri_contact_id, sec_contact_id, blah_blah)
VALUES(1, 3, "Team A"), (4, 2, "Team B"), (1, NULL, "Team A");
Run Code Online (Sandbox Code Playgroud)
请注意具有sec_contact_id= NULL-的最终记录,请参阅EDIT下面的讨论。我隐含地假设团队身份是由pri_contact_id- 定义为必要的。
您还会注意到我使用snake_case或lower_case_with_underscores- 个人喜好 - 选择一种风格并坚持下去!.
我在小提琴中的 SQL 中留下了额外的字段,以便您可以看到所涉及的思维过程以及我是如何找到解决方案的!
SELECT
nl1.id, nl1.contact_id, nl1.contact_name,
ci1.pri_contact_id, ci1.sec_contact_id, ci1.blah_blah
FROM name_lookup nl1
JOIN contact_info ci1
ON nl1.contact_id = ci1.pri_contact_id;
Run Code Online (Sandbox Code Playgroud)
结果:
id contact_id contact_name pri_contact_id sec_contact_id blah_blah
1 1 John Doe 1 3 Team A
4 4 Larry Brown 4 2 Team B
Run Code Online (Sandbox Code Playgroud)
因此,现在我们name_lookup使用contact_info它们之间的链接重新连接自身。
SELECT
nl1.id, nl1.contact_id, nl1.contact_name,
nl2.id, nl2.contact_id, nl2.contact_name,
ci1.pri_contact_id, ci1.sec_contact_id, ci1.blah_blah
FROM name_lookup nl1
JOIN contact_info ci1
ON nl1.contact_id = ci1.pri_contact_id
JOIN name_lookup nl2
ON ci1.sec_contact_id = nl2.contact_id
ORDER BY nl1.id;
Run Code Online (Sandbox Code Playgroud)
结果:
id contact_id contact_name id contact_id contact_name pri_contact_id sec_contact_id blah_blah
1 1 John Doe 3 3 Jose Garcia 1 3 Team A
4 4 Larry Brown 2 2 Mary Smith 4 2 Team B
Run Code Online (Sandbox Code Playgroud)
因此,获得我们的结果后,我们现在可以按如下方式清理 SQL(仅SELECT必填字段 - 减少任何网络流量以及服务器上的 I/O):
SELECT
nl1.contact_name AS "Con_1 name",
nl2.contact_name AS "Con_2 name",
ci1.blah_blah AS "Team"
FROM name_lookup nl1
JOIN contact_info ci1
ON nl1.contact_id = ci1.pri_contact_id
JOIN name_lookup nl2
ON ci1.sec_contact_id = nl2.contact_id
ORDER BY nl1.id;
Run Code Online (Sandbox Code Playgroud)
结果:
Con_1 name Con_2 name Team
John Doe Jose Garcia Team A
Larry Brown Mary Smith Team B
Run Code Online (Sandbox Code Playgroud)
Et voilà - 结果如愿!
EDIT (NULLs in sec_contact_id):有人向我指出,我的回答并不像我希望的那样全面。如果sec_contact_id是NULL这毕竟是可能的-你可能已经取得了第一个,但后续尚未完成?
所以,我略微改变了表,它现在包含(您将看到上面-一个相当大的变化小提琴,请在这里-我想在PostgreSQL上运行它也可以):
Con_1 name Con_2 name Team
John Doe Jose Garcia Team A
John Doe NULL Team B
Larry Brown Mary Smith Team B
Run Code Online (Sandbox Code Playgroud)
所以,现在,你必须这样使用INNER JOINs:
nl1.contact_name AS "Con_1 name",
nl2.contact_name AS "Con_2 name",
ci1.blah_blah AS "Team"
FROM contact_info ci1
LEFT JOIN name_lookup nl1
ON nl1.contact_id = ci1.pri_contact_id
LEFT JOIN name_lookup nl2
ON nl2.contact_id = ci1.sec_contact_id
ORDER BY nl1.id, ci1.blah_blah;
Run Code Online (Sandbox Code Playgroud)
结果:
Con_1 name Con_2 name Team
John Doe Jose Garcia Team A
John Doe NULL Team B
Larry Brown Mary Smith Team B
Run Code Online (Sandbox Code Playgroud)
因此,现在带有sec_contact_id = NULL数据的记录出现在您的结果集中。
几句忠告:
你真的应该考虑(强烈)考虑从 5.6 升级到 MySQL 8 的当前版本——你会得到窗口函数、生成的列、CHECK约束——它现在是 22 版,我没有听到很多抱怨,所以它会是个不错的选择!
许多人认为NULLs 是不受欢迎的,并像躲避瘟疫一样避开它们 - 我倾向于属于这一类。因此,您可能希望考虑拥有两个联系表 -pri_contact_info和sec_contact_info. 您可以决定是否要这样做并提出一个新问题 - 如果您这样做,请在此处告诉我!
您可能会考虑回答这个问题(原始帖子下方的评论)Can there ever be more than two people on a team? I e. There would be 3 columns with team members names for the same row?:!
在PRIMARY KEY对的name_lookup表应该是contact_id-在代理键 id添加任何的组合!我假设contact_id在雇用员工时或多或少随机分配给他们?所以,它本质上是一个代理键本身。代理键有自己的位置,但有时它们不是可行的方法!
在标准支持方面,MySQL 无疑是主要 RDBMS 中最糟糕的,而且它有大量的非标准"extensions"- 将来,也许您可以用撇号'而不是双引号来分隔 SQL 字符串"?我的个人suggestion是,您像我一样对最终结果(演示,而不是内容)的字段名称的别名使用双引号 - 这将使您的 SQL 更具可读性和可移植性!
| 归档时间: |
|
| 查看次数: |
141 次 |
| 最近记录: |