JavaRush /Java Blog /Random-TW /我們分析資料庫和 SQL 語言。(第 5 部分 - 連接和聯接) - “Java 專案從 A 到 Z”
Roman Beekeeper
等級 35

我們分析資料庫和 SQL 語言。(第 5 部分 - 連接和聯接) - “Java 專案從 A 到 Z”

在 Random-TW 群組發布
有關建立 Java 專案的系列文章中的一篇文章(其他資料的連結位於最後)。其目標是分析關鍵技術,結果是編寫一個電報機器人。 大家好,未來的軟體老年人和老年人。正如我在上一部分(檢查作業)所說,今天會有新材料。對於那些特別渴望的人,我挖了一個有趣的作業,以便那些已經知道一切的人和那些不知道但想谷歌的人可以練習和測試他們的技能。「Java 專案從頭到尾」:我們分析資料庫和 SQL 語言。 第 5 部分 - 連接與連接 - 1今天我們將討論連接和聯接的類型。

資料庫中的關係類型

「Java 專案從頭到尾」:我們分析資料庫和 SQL 語言。 第 5 部分 - 連接與連接 - 2要理解什麼是關係,您需要記住什麼是外鍵。對於那些忘記的人,歡迎來到本系列的開頭

一對多

讓我們記住我們的國家和城市的例子。顯然,一個城市必須有一個國家。如何將國家與城市連結?有必要為每個城市附加其所屬國家的唯一識別碼(ID):我們已經這樣做了。這被稱為連接類型之一 -一對多(最好了解英文版本 - 一對多)。換句話說,我們可以說:幾個城市可以屬於一個國家。這就是您應該記住的方式:一對多關係。到目前為止已經很清楚了,對吧?如果沒有,那麼「Java 專案從頭到尾」:我們分析資料庫和 SQL 語言。 第 5 部分 - 連接與連接 - 3這是來自網路的第一張圖片: 它顯示有客戶和他們的訂單。一位客戶可以有多個訂單,這是有道理的。有一對多:) 或另一個例子:「Java 專案從頭到尾」:我們分析資料庫和 SQL 語言。 第 5 部分 - 連接與連接 - 4有三個表:出版商、作者和書籍。每個不想破產、想要成功的出版商都有不只一位作者,你不同意嗎?反過來,每個作者可能擁有不只一本書——這一點也是毫無疑問的。這又意味著一位作者與多本書的聯繫,一位出版商與多位作者的聯繫。還有很多例子可以舉出。一開始感知的困難可能只在於學習抽象思考:從外部觀察桌子及其互動。

一對一(一對一)

這可以說是一對多通訊的一個特例。一個表中的一筆記錄僅與另一表中的一筆記錄相關的情況。生活中還能有哪些例子呢?如果我們排除一夫多妻制,那麼我們可以說夫妻之間是一對一的關係。雖然即使我們說允許一夫多妻制,但每個妻子仍然只能擁有一個丈夫。對於父母來說也是如此。每個人只能有一位親生父親和一位親生母親。明確的一對一關係。當我寫這篇文章時,我想到了一個想法:如果一對一關係已經具有一對一關係,為什麼還要將一對一關係劃分為不同表中的兩條記錄?我自己想出了答案。這些記錄還可以透過其他方式連結到其他記錄。我在說什麼?一對一聯繫的另一個例子是國家和總統之間。是否可以在「國家」表中寫下所有有關總統的數據?是的,可以,SQL 不會說一句話。但如果你認為總統也是一個人……而且他可能還有妻子(另一個一對一的關係)和孩子(另一種一對多的關係),然後事實證明會是將國家與總統的妻子和孩子連結起來是必要的… 聽起來很瘋狂,對吧?:D 這種關聯還有很多其他的例子。此外,在這種情況下,您可以為兩個表添加外鍵,這與一對多關係不同。

多對多

根據名字,你就可以猜到我們要討論的內容了。在生活中,當我們規劃我們的生活時,經常會出現上述類型的連結不足以描述我們需要的東西的情況。我們已經討論過出版商、書籍和作者。這裡有太多的聯繫......每個出版物都可以有多個作者 - 一對多的聯繫。同時,每個作者可能有多個出版商(為什麼不呢,例如,作者在一個地方出版,為錢吵架,去了另一家出版社)。這又是一對多的關係。或者這樣:每個作者可以有幾本書,但每本書也可以有多位作者。再次強調,作者與書籍、書籍與作者之間是一對多的關係。從這個例子我們可以得到一個更形式化的結論:

假設我們有兩個表A和B。

A 可以與 B 建立一對多的關係。

但 B 也可以與 A 相關,就像一與多相關一樣。

這意味著它們具有多對多關係。

很清楚如何在 SQL 中設定前面的連線類型:我們只需將該連線類型的 ID 傳遞給那些記錄,這些記錄有很多,對嗎?一個國家將其 ID 作為許多城市的外鍵。如何處理多對多關係?這種方法不適合。我們需要新增另一個表來連接這兩個表。例如,讓我們進入 MySQL,建立一個新資料庫 Manytomany,建立兩個表,author 和 book,其中僅包含姓名及其 ID: CREATE DATABASE Manytomany; 使用多對多;建立表格作者(id INT AUTO_INCRMENT,名稱VARCHAR(100),主鍵(id));建立表格 book( id INT AUTO_INCRMENT, name VARCHAR(100), PRIMARY KEY (id) ); 「Java 專案從頭到尾」:我們分析資料庫和 SQL 語言。 第 5 部分 - 連接與連接 - 5現在讓我們建立第三個表,該表將具有來自作者和書籍表的兩個外鍵,並且此連結將是唯一的。也就是說,不可能兩次添加具有相同鍵的記錄: CREATE TABLEauthors_x_books ( book_id INT NOT NULL,author_id INT NOT NULL, FOREIGN KEY (book_id) REFERENCES book(id), FOREIGN KEY (author_id) REFERENCES Author (id),唯一(book_id,author_id));「Java 專案從頭到尾」:我們分析資料庫和 SQL 語言。 第 5 部分 - 連接與連接 - 6這裡我們使用了幾個新特性,需要單獨註解:
  • NOT NULL 表示欄位必須始終填寫,如果我們不填寫,SQL 會告訴我們;
  • UNIQUE 表示一個欄位或一組欄位在表格中必須是唯一的。經常發生的情況是,除了唯一識別碼之外,每個記錄還必須有一個欄位是唯一的。而UNIQUE正是負責這件事情的。
根據我的實踐:當從舊系統遷移到新系統時,我們作為開發人員必須儲存舊系統的 ID 以便使用它並創建我們自己的系統。為什麼要創建自己的而不是使用舊的?它們可能不夠獨特,或者這種創建 ID 的方法可能不再相關且受到限制。為此,我們使舊的 ID 名稱在表中也是唯一的。要檢查這一點,您需要新增資料。新增書籍和作者: NSERT INTO book (name) VALUES ("book1"); INSERT INTO 作者(姓名)VALUES(“author1”); 我們從先前的文章中已經知道它們的ID為1和1。因此,我們可以立即在第三個表格中新增一筆記錄: INSERT INTOauthors_x_booksVALUES(1,1); 一切都會很好,直到我們想再次重複最後一個命令:也就是說,再次寫下相同的 ID:「Java 專案從頭到尾」:我們分析資料庫和 SQL 語言。 第 5 部分 - 連接與連接 - 7結果將很自然 - 一個錯誤。會有重複的。該條目不會被記錄。這就是創建多對多連接的方式...所有這一切都非常酷且有趣,但是出現了一個邏輯問題:如何獲取這些資訊?如何將不同表中的資料組合在一起並得到一個答案?這就是我們將在下一部分中討論的內容))

連接(連接)

在上一部分中,我幫助您立即了解連接是什麼以及在哪裡使用它們。因為我深信,一旦理解了,一切都會立即變得非常簡單,所有關於聯接的文章都會像嬰兒的眼睛一樣清晰:D 粗略地講,聯接是通過某種方式從多個表中獲取結果JOIN(來自英語join 的連結)。這就是全部...)要連接,您需要指定連接表的欄位。魔鬼並不像畫中的那麼可怕,對吧?)接下來,我們只討論連接有哪些類型以及如何使用它們。連接的類型有很多種,我們不會全部考慮。只有那些我們真正需要的。這就是為什麼我們對 Cross 和 Natural 這樣的奇異連接不感興趣。我完全忘記了,我們需要記住一個細微差別:表格和欄位可以有別名- 假名。它們可以方便地用於連接。例如,您可以這樣做: SELECT * FROM table1; 如果查詢經常使用table1,那麼你可以給它一個別名: SELECT* FROM table1 as t1; 或更容易寫: SELECT * FROM table1 t1; 然後稍後在查詢中可以使用t1作為該表的別名。

內部聯接

最常見、最簡單的連結。它表示,當我們有兩個表和一個可以連接它的欄位時,將選擇兩個表中存在關係的所有記錄。不知何故很難說。讓我們來看一個例子:讓我們為城市資料庫新增一筆記錄。一項用於城市,一項用於國家: $ INSERT INTO Country VALUES(5, "Uzbekistan", 34036800); $ INSERT INTO city (名稱, 人口) VALUES("第比利斯", 1171100); 我們新增了一個在表中沒有城市的國家/地區,以及一個與表中的國家/地區沒有關聯的城市。因此,INNER JOIN 致力於為兩個表中的連接發布所有記錄。當我們想要連接兩個表 table1 和 table2 時,一般語法如下所示: SELECT * FROM table1 t1 INNER JOIN table2 ON t1.id = t2.t1_id; 然後將傳回兩個表中具有關係的所有記錄。對於我們的例子,當我們想要接收國家和城市的資訊時,結果將是這樣的: $ SELECT * FROM city ci INNER JOIN Country co ON ci.country_id = co.id; 「Java 專案從頭到尾」:我們分析資料庫和 SQL 語言。 第 5 部分 - 連接與連接 - 8在這裡,雖然名稱相同,但您可以清楚地看到城市的字段在前,然後是國家的字段。但我們上面新增的兩個條目不存在。因為這正是 INNER JOIN 的工作原理。

左連接

在某些情況下,而且經常是,我們對主表的欄位遺失不滿意,因為相鄰表中沒有該欄位的記錄。這就是 LEFT JOIN 的用途。如果在先前的請求中我們指定 LEFT 而不是 INNER,我們將在回應中新增另一個城市 - 提比里斯: $ SELECT * FROM city ci LEFT JOIN Country co ON ci.country_id = co.id; 「Java 專案從頭到尾」:我們分析資料庫和 SQL 語言。 第 5 部分 - 連接與連接 - 9有一個關於第比利斯的新條目,與該國家相關的所有內容均為null。這就是它經常被使用的方式。

右邊連接

這裡與 LEFT JOIN 的差異在於,所有欄位都不會選擇在左側,而是在連接的右側。也就是說,不是城市,而是所有國家: $ SELECT * FROM city ci RIGHT JOIN Country co ON ci.country_id = co.id; 「Java 專案從頭到尾」:我們分析資料庫和 SQL 語言。 第 5 部分 - 連接與連接 - 10現在很明顯,在這種情況下,不會有第比利斯,但我們會有烏茲別克。類似的東西......))

保護連接

現在我想向你們展示一張初級人員在面試前死記硬背的典型圖片,以讓他們相信自己了解連接的本質:「Java 專案從頭到尾」:我們分析資料庫和 SQL 語言。 第 5 部分 - 連接與連接 - 11這裡一切都以集合的形式顯示,每個圓圈都是一個表。那些被覆蓋的地方就是那些會在 SELECT 中顯示的部分。我們看看吧:
  • INNER JOIN 只是集合的交集,即那些與兩個表 A 和 B 有連接的記錄;
  • LEFT JOIN 是表 A 中的所有記錄,包括表 B 中與 A 有交集(連接)的所有記錄;
  • RIGHT JOIN 與 LEFT JOIN 完全相反 - 表 B 中的所有記錄與 A 中的記錄都有關係。
經過這一切,這張圖應該很清楚了))

家庭作業

這次的任務將非常有趣,所有成功解決它們的人都可以放心,他們已經準備好開始在 SQL 方面工作了!這些任務沒有經過咀嚼,是為中學生寫的,所以對你來說不會容易和無聊:)我會給你一周的時間自己做任務,然後我會單獨發表一篇文章進行詳細分析我給你的任務的解決方案。

實際任務:

  1. 編寫一個 SQL 腳本來建立包含以下欄位的「學生」表:id(主鍵)、name、last_name、e_mail(唯一)。
  2. 編寫一個 SQL 腳本來建立包含以下欄位的「Book」表:id、title(id + title = 主鍵)。透過「學生」一對多「書籍」關係連結「學生」和「書籍」。
  3. 編寫一個 SQL 腳本來建立包含以下欄位的「教師」表:id(主鍵)、姓名、姓氏、電子郵件(唯一)、主題。
  4. 透過「學生」多對多教師的關係連結「學生」和「教師」。
  5. 選擇姓氏含有“oro”的“學生”,例如“Sid oro v”、“V oro novsky”。
  6. 從「學生」表中選擇所有姓氏 ('last_name') 及其重複次數。考慮一下資料庫中有同名的人。按數量降序排列。它應該看起來像這樣:
    數量
    彼得羅夫 15
    伊凡諾夫 12
    西多羅夫 3
  7. 從「學生」中選擇重複次數最多的 3 個姓名。按數量降序排列。它應該看起來像這樣:
    姓名 數量
    亞歷山大 27
    謝爾蓋 10
    彼得 7
  8. 選擇擁有最多「書籍」數量的「學生」和關聯的「老師」。按數量降序排列。它應該看起來像這樣:
    老師的姓氏 學生的姓氏 書籍數量
    彼得羅夫 西多羅夫 7
    伊凡諾夫 史密斯 5
    彼得羅夫 坎卡瓦 2>
  9. 從所有“學生”中選擇擁有最多“書籍”數量的“老師”。按數量降序排列。它應該看起來像這樣:
    老師的姓氏 書籍數量
    彼得羅夫 9
    伊凡諾夫 5
  10. 選擇其所有“學生”的“書籍”數量在 7 到 11 之間的“老師”。按數量降序排列。它應該看起來像這樣:
    老師的姓氏 書籍數量
    彼得羅夫 十一
    西多羅夫 9
    伊凡諾夫 7
  11. 列印所有“教師”和“學生”的所有“姓氏”和“姓名”,欄位“類型”(學生或教師)。按“姓氏”字母順序排序。它應該看起來像這樣:
    類型
    伊凡諾夫 學生
    坎卡瓦 老師
    史密斯 學生
    西多羅夫 老師
    彼得羅夫 老師
  12. 將「rate」欄位新增至現有的「Student」表中,該欄位將儲存學生目前所在的課程(數值從 1 到 6)。
  13. 該項目不是必需的,但會是優點。編寫一個函數,該函數將遍歷所有“書籍”並輸出以逗號分隔的所有“標題”。

結論

關於資料庫的系列有點拖沓了。同意。然而,我們已經走了很長的路,結果我們對此事有了了解!感謝大家的閱讀,我提醒大家,每個想要繼續並關注該專案的人都需要在GitHub上建立一個帳戶並訂閱我的帳戶:) 更多內容 - 讓我們談談 Maven 和 Docker。感謝大家的閱讀。我再說一次:走的人才能掌握路;)

此系列所有資料的清單位於本文開頭。

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION