多列上的相同連接約束
我們有一種情況,我可以通過以下簡單範例重新創建。我有以下兩個範例表:
CREATE TABLE contact_info ( id INT UNSIGNED AUTO_INCREMENT, priContactId INT, secContactId INT, blahBlah VARCHAR(32), PRIMARY KEY(id) );
和
CREATE TABLE name_lookup ( id INT UNSIGNED AUTO_INCREMENT, contactID INT, contactName VARCHAR(32), PRIMARY KEY(id) );
我將它們填充如下:
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");
顯然,表格的內容如下:
+----+--------------+--------------+----------+ | 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 | +----+-----------+-------------+
我們想執行一個 JOIN 操作,以便我們得到這樣的輸出:
+-------------+-------------+--------+ | John Doe | Jose Garcia | Team A | +-------------+-------------+--------+ | Larry Brown | Mary Smith | Team B | +-------------+-------------+--------+
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) );
填充它們:
INSERT INTO name_lookup(contact_id, contact_name) VALUES (1, "John Doe"), (2, "Mary Smith"), (3, "Jose Garcia"), (4, "Larry Brown");
和
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");
請注意具有
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;
結果:
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
因此,現在我們使用它們之間的連結
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;
結果:
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
因此,在獲得結果後,我們現在可以清理 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;
結果:
Con_1 name Con_2 name Team John Doe Jose Garcia Team A Larry Brown Mary Smith Team B
等等 - 結果如願!
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
所以,現在,你必須使用
INNER JOIN
s :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;
結果:
Con_1 name Con_2 name Team John Doe Jose Garcia Team A John Doe NULL Team B Larry Brown Mary Smith Team B
因此,現在帶有
sec_contact_id = NULL
基準的記錄出現在您的結果集中。幾句忠告:
- 你真的應該考慮(強烈)考慮從 5.6 升級到 MySQL 8 的目前版本——你會得到視窗函式、生成的列、
CHECK
約束——現在是 22 版,我沒有聽到很多抱怨,所以它會是一個不錯的選擇!- 許多人認為
NULL
s 是不受歡迎的,並像瘟疫一樣避免它們——我傾向於屬於這一類。因此,您可能希望考慮擁有兩個聯繫人表 -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 更具可讀性和可移植性!