如何使用 SQL INNER JOIN 聯結兩個或多個表

来源:https://www.cnblogs.com/vin-c/archive/2022/05/17/16279509.html
-Advertisement-
Play Games

本文介紹什麼是 SQL INNER JOIN 聯結,為什麼使用聯結,如何編寫使用聯結的 SELECT 語句。並講述了一些關係資料庫設計的基本知識,包括等值聯結(也稱為內聯結)這種最常用的聯結。 一、聯結 SQL 最強大的功能之一就是能在數據查詢的執行中聯結(join)表。聯結是利用 SQL 的 SE ...


目錄

本文介紹什麼是 SQL INNER JOIN 聯結,為什麼使用聯結,如何編寫使用聯結的 SELECT 語句。並講述了一些關係資料庫設計的基本知識,包括等值聯結(也稱為內聯結)這種最常用的聯結。

一、聯結

SQL 最強大的功能之一就是能在數據查詢的執行中聯結(join)表。聯結是利用 SQL 的 SELECT 能執行的最重要的操作,很好地理解聯結及其語法是學習 SQL 的極為重要的部分。

在能夠有效地使用聯結前,必須瞭解關係表以及關係資料庫設計的一些基礎知識。下麵的介紹並不能涵蓋這一主題的所有內容,但作為入門已經夠了。

1.1 關係表

理解關係表,最好是來看個例子。

有一個包含產品目錄的資料庫表,其中每類物品占一行。對於每一種物品,要存儲的信息包括產品描述、價格,以及生產該產品的供應商。

現在有同一供應商生產的多種物品,那麼在何處存儲供應商名、地址、聯繫方法等供應商信息呢?將這些數據與產品信息分開存儲的理由是:

  • 同一供應商生產的每個產品,其供應商信息都是相同的,對每個產品重覆此信息既浪費時間又浪費存儲空間;
  • 如果供應商信息發生變化,例如供應商遷址或電話號碼變動,只需修改一次即可;
  • 如果有重覆數據(即每種產品都存儲供應商信息),則很難保證每次輸入該數據的方式都相同。不一致的數據在報表中就很難利用。

關鍵是,相同的數據出現多次決不是一件好事,這是關係資料庫設計的基礎。

關係表的設計就是要把信息分解成多個表,一類數據一個表。各表通過某些共同的值互相關聯(所以才叫關係資料庫)。

在這個例子中可建立兩個表:一個存儲供應商信息,另一個存儲產品信息。Vendors 表包含所有供應商信息,每個供應商占一行,具有唯一的標識。

此標識稱為主鍵(primary key),可以是供應商 ID 或任何其他唯一值。

Products 表只存儲產品信息,除了存儲供應商 IDVendors 表的主鍵)外,它不存儲其他有關供應商的信息。

Vendors 表的主鍵將 Vendors 表與 Products 表關聯,利用供應商 ID 能從 Vendors 表中找出相應供應商的詳細信息。

這樣做的好處是:

  • 供應商信息不重覆,不會浪費時間和空間;
  • 如果供應商信息變動,可以只更新 Vendors 表中的單個記錄,相關表中的數據不用改動;
  • 由於數據不重覆,數據顯然是一致的,使得處理數據和生成報表更簡單。

總之,關係數據可以有效地存儲,方便地處理。因此,關係資料庫的可伸縮性遠比非關係資料庫要好。

可伸縮(scale)

能夠適應不斷增加的工作量而不失敗。設計良好的資料庫或應用程式稱為可伸縮性好(scale well)。

1.2 為什麼使用聯結

如前所述,將數據分解為多個表能更有效地存儲,更方便地處理,並且可伸縮性更好。但這些好處是有代價的。

如果數據存儲在多個表中,怎樣用一條 SELECT 語句就檢索出數據呢?

答案是使用聯結。簡單說,聯結是一種機制,用來在一條 SELECT 語句中關聯表,因此稱為聯結。使用特殊的語法,可以聯結多個表返回一組輸出,聯結在運行時關聯表中正確的行。

說明:使用互動式 DBMS 工具

重要的是,要理解聯結不是物理實體。換句話說,它在實際的資料庫表中並不存在。DBMS 會根據需要建立聯結,它在查詢執行期間一直存在。

許多 DBMS 提供圖形界面,用來互動式地定義表關係。這些工具極其有助於維護引用完整性。在使用關係表時,僅在關係列中插入合法數據是非常重要的。

回到這裡的例子,如果 Products 表中存儲了無效的供應商 ID,則相應的產品不可訪問,因為它們沒有關聯到某個供應商。

為避免這種情況發生,可指示資料庫只允許在 Products 表的供應商 ID 列中出現合法值(即出現在 Vendors 表中的供應商)。

引用完整性表示 DBMS 強制實施數據完整性規則。這些規則一般由提供了界面的 DBMS 管理。

二、創建聯結

創建聯結非常簡單,指定要聯結的所有表以及關聯它們的方式即可。請看下麵的例子:

SELECT vend_name, prod_name, prod_price
FROM Vendors, Products
WHERE Vendors.vend_id = Products.vend_id;

輸出:

vend_name                prod_name                prod_price
--------------------     --------------------     ----------
Doll House Inc.          Fish bean bag toy        3.4900
Doll House Inc.          Bird bean bag toy        3.4900
Doll House Inc.          Rabbit bean bag toy      3.4900
Bears R Us               8 inch teddy bear        5.9900
Bears R Us               12 inch teddy bear       8.9900
Bears R Us               18 inch teddy bear       11.9900
Doll House Inc.          Raggedy Ann              4.9900
Fun and Games            King doll                9.4900
Fun and Games            Queen doll               9.4900

我們來看這段代碼。

SELECT 語句與前面所有語句一樣指定要檢索的列。這裡最大的差別是所指定的兩列(prod_nameprod_price)在一個表中,而第一列(vend_name)在另一個表中。

現在來看 FROM 子句。

與以前的 SELECT 語句不一樣,這條語句的 FROM 子句列出了兩個表:VendorsProducts

它們就是這條 SELECT 語句聯結的兩個表的名字。這兩個表用 WHERE 子句正確地聯結,WHERE 子句指示 DBMS 將 Vendors 表中的 vend_idProducts 表中的 vend_id 匹配起來。

可以看到,要匹配的兩列指定為 Vendors.vend_idProducts.vend_id。這裡需要這種完全限定列名,如果只給出 vend_id,DBMS 就不知道指的是哪一個(每個表中有一個)。

從前面的輸出可以看到,一條 SELECT 語句返回了兩個不同表中的數據。

警告:完全限定列名

就像 如何在 SQL 中使用子查詢 提到的,在引用的列可能出現歧義時,必須使用完全限定列名(用一個句點分隔表名和列名)。

如果引用一個沒有用表名限制的具有歧義的列名,大多數 DBMS 會返回錯誤。

2.1 WHERE 子句的重要性

使用 WHERE 子句建立聯結關係似乎有點奇怪,但實際上是有個很充分的理由的。

要記住,在一條 SELECT 語句中聯結幾個表時,相應的關係是在運行中構造的。在資料庫表的定義中沒有指示 DBMS 如何對錶進行聯結的內容。你必須自己做這件事情。

在聯結兩個表時,實際要做的是將第一個表中的每一行與第二個表中的每一行配對。

WHERE 子句作為過濾條件,只包含那些匹配給定條件(這裡是聯結條件)的行。沒有 WHERE 子句,第一個表中的每一行將與第二個表中的每一行配對,而不管它們邏輯上是否能配在一起。

笛卡兒積(cartesian product)

由沒有聯結條件的表關係返回的結果為笛卡兒積。檢索出的行的數目將是第一個表中的行數乘以第二個表中的行數。

理解這一點,請看下麵的 SELECT 語句及其輸出:

SELECT vend_name, prod_name, prod_price
FROM Vendors, Products;

輸出:

vend_name           prod_name                       prod_price
----------------    ----------------------------    ----------
Bears R Us          8 inch teddy bear               5.99
Bears R Us          12 inch teddy bear              8.99
Bears R Us          18 inch teddy bear              11.99
Bears R Us          Fish bean bag toy               3.49
Bears R Us          Bird bean bag toy               3.49
Bears R Us          Rabbit bean bag toy             3.49
Bears R Us          Raggedy Ann                     4.99
Bears R Us          King doll                       9.49
Bears R Us          Queen doll                      9.49
Bear Emporium       8 inch teddy bear               5.99
Bear Emporium       12 inch teddy bear              8.99
Bear Emporium       18 inch teddy bear              11.99
Bear Emporium       Fish bean bag toy               3.49
Bear Emporium       Bird bean bag toy               3.49
Bear Emporium       Rabbit bean bag toy             3.49
Bear Emporium       Raggedy Ann                     4.99
Bear Emporium       King doll                       9.49
Bear Emporium       Queen doll                      9.49
Doll House Inc.     8 inch teddy bear               5.99
Doll House Inc.     12 inch teddy bear              8.99
Doll House Inc.     18 inch teddy bear              11.99
Doll House Inc.     Fish bean bag toy               3.49
Doll House Inc.     Bird bean bag toy               3.49
Doll House Inc.     Rabbit bean bag toy             3.49
Doll House Inc.     Raggedy Ann                     4.99
Doll House Inc.     King doll                       9.49
Doll House Inc.     Queen doll                      9.49
Furball Inc.        8 inch teddy bear               5.99
Furball Inc.        12 inch teddy bear              8.99
Furball Inc.        18 inch teddy bear              11.99
Furball Inc.        Fish bean bag toy               3.49
Furball Inc.        Bird bean bag toy               3.49
Furball Inc.        Rabbit bean bag toy             3.49
Furball Inc.        Raggedy Ann                     4.99
Furball Inc.        King doll                       9.49
Furball Inc.        Queen doll                      9.49
Fun and Games       8 inch teddy bear               5.99
Fun and Games       12 inch teddy bear              8.99
Fun and Games       18 inch teddy bear              11.99
Fun and Games       Fish bean bag toy               3.49
Fun and Games       Bird bean bag toy               3.49
Fun and Games       Rabbit bean bag toy             3.49
Fun and Games       Raggedy Ann                     4.99
Fun and Games       King doll                       9.49
Fun and Games       Queen doll                      9.49
Jouets et ours      8 inch teddy bear               5.99
Jouets et ours      12 inch teddy bear              8.99
Jouets et ours      18 inch teddy bear              11.99
Jouets et ours      Fish bean bag toy               3.49
Jouets et ours      Bird bean bag toy               3.49
Jouets et ours      Rabbit bean bag toy             3.49
Jouets et ours      Raggedy Ann                     4.99
Jouets et ours      King doll                       9.49
Jouets et ours      Queen doll                      9.49

從上面的輸出可以看到,相應的笛卡兒積不是我們想要的。這裡返回的數據用每個供應商匹配了每個產品,包括了供應商不正確的產品(即使供應商根本就沒有產品)。

註意:不要忘了 WHERE 子句

要保證所有聯結都有 WHERE 子句,否則 DBMS 將返回比想要的數據多得多的數據。

同理,要保證 WHERE 子句的正確性。不正確的過濾條件會導致 DBMS 返回不正確的數據。

提示:叉聯結

有時,返回笛卡兒積的聯結,也稱叉聯結(cross join)。

2.2 內聯結

目前為止使用的聯結稱為等值聯結(equijoin),它基於兩個表之間的相等測試。這種聯結也稱為內聯結(inner join)。其實,可以對這種聯結使用稍微不同的語法,明確指定聯結的類型。

下麵的 SELECT 語句返回與前面例子完全相同的數據:

SELECT vend_name, prod_name, prod_price
FROM Vendors
INNER JOIN Products ON Vendors.vend_id = Products.vend_id;

此語句中的 SELECT 與前面的 SELECT 語句相同,但 FROM 子句不同。

這裡,兩個表之間的關係是以 INNER JOIN 指定的部分 FROM 子句。

在使用這種語法時,聯結條件用特定的 ON 子句而不是 WHERE 子句給出。傳遞給 ON 的實際條件與傳遞給 WHERE 的相同。

至於選用哪種語法,請參閱具體的 DBMS 文檔。

說明:“正確的”語法

ANSI SQL 規範首選 INNER JOIN 語法,之前使用的是簡單的等值語法。

其實,SQL 語言純正論者是用鄙視的眼光看待簡單語法的。

這就是說,DBMS 的確支持簡單格式和標準格式,我建議你要理解這兩種格式,具體使用就看你用哪個更順手了。

2.3 聯結多個表

SQL 不限制一條 SELECT 語句中可以聯結的表的數目。創建聯結的基本規則也相同。首先列出所有表,然後定義表之間的關係。例如:

SELECT prod_name, vend_name, prod_price, quantity
FROM OrderItems, Products, Vendors
WHERE Products.vend_id = Vendors.vend_id
 AND OrderItems.prod_id = Products.prod_id
 AND order_num = 20007;

輸出:

prod_name           vend_name         prod_price     quantity
---------------     -------------     ----------     --------
18 inch teddy bear  Bears R Us        11.9900        50
Fish bean bag toy   Doll House Inc.   3.4900         100
Bird bean bag toy   Doll House Inc.   3.4900         100
Rabbit bean bag toy Doll House Inc.   3.4900         100
Raggedy Ann         Doll House Inc.   4.9900         50

這個例子顯示訂單 20007 中的物品。訂單物品存儲在 OrderItems 表中。每個產品按其產品 ID 存儲,它引用 Products 表中的產品。

這些產品通過供應商 ID 聯結到 Vendors 表中相應的供應商,供應商 ID 存儲在每個產品的記錄中。

這裡的 FROM 子句列出三個表,WHERE 子句定義這兩個聯結條件,而第三個聯結條件用來過濾出訂單 20007 中的物品。

註意:性能考慮

DBMS 在運行時關聯指定的每個表,以處理聯結。這種處理可能非常耗費資源,因此應該註意,不要聯結不必要的表。聯結的表越多,性能下降越厲害。

註意:聯結中表的最大數目

雖然 SQL 本身不限制每個聯結約束中表的數目,但實際上許多 DBMS 都有限制。請參閱具體的 DBMS 文檔以瞭解其限制。

現在回顧一下 如何在 SQL 中使用子查詢 中的例子,如下的 SELECT 語句返回訂購產品 RGAN01 的顧客列表:

SELECT cust_name, cust_contact
FROM Customers
WHERE cust_id IN (SELECT cust_id
                  FROM Orders
                  WHERE order_num IN (SELECT order_num
                                      FROM OrderItems
                                      WHERE prod_id = 'RGAN01'));

如何在 SQL 中使用子查詢 所述,子查詢並不總是執行複雜 SELECT 操作的最有效方法,下麵是使用聯結的相同查詢:

SELECT cust_name, cust_contact
FROM Customers, Orders, OrderItems
WHERE Customers.cust_id = Orders.cust_id
 AND OrderItems.order_num = Orders.order_num
 AND prod_id = 'RGAN01';

輸出:

cust_name                         cust_contact
-----------------------------     --------------------
Fun4All                           Denise L. Stephens
The Toy Store                     Kim Howard

如何在 SQL 中使用子查詢 所述,這個查詢中的返回數據需要使用 3 個表。

但在這裡,我們沒有在嵌套子查詢中使用它們,而是使用了兩個聯結來連接表。這裡有三個 WHERE 子句條件。前兩個關聯聯結中的表,後一個過濾產品 RGAN01 的數據。

提示:多做實驗

可以看到,執行任一給定的 SQL 操作一般不止一種方法。很少有絕對正確或絕對錯誤的方法。

性能可能會受操作類型、所使用的 DBMS、表中數據量、是否存在索引或鍵等條件的影響。

因此,有必要試驗不同的選擇機制,找出最適合具體情況的方法。

說明:聯結的列名

上述所有例子里,聯結的幾個列的名字都是一樣的(例如 CustomersOrders 表裡的列都叫 cust_id)。

列名相同並不是必需的,而且你經常會遇到命名規範不同的資料庫。我這樣建表只是為了簡單起見。

三、小結

聯結是 SQL 中一個最重要、最強大的特性,有效地使用聯結需要對關係資料庫設計有基本的瞭解。

本文在介紹聯結時,講述了一些關係資料庫設計的基本知識,包括等值聯結(也稱為內聯結)這種最常用的聯結。

SQL 如何使用自聯結、自然聯結和外聯結 介紹如何創建其他類型的聯結。

原文鏈接:https://www.developerastrid.com/sql/sql-inner-join/

(完)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 1.下載WSL Ubuntu 打開微軟商店,搜索linux,找到Ubuntu並下載 2.安裝WSL Ubuntu 下載完成以後先不要安裝,因為預設安裝位置是在c盤,此時在其他盤新建一個文件夾,打開C:\Program Files\WindowsA ...
  • 前言: 這是《VMware 虛擬機圖文安裝和配置 Rocky Linux 8.5 教程》一文的姐妹篇教程,如果你需要閱讀它,請點擊這裡。 2020 年,CentOS 宣佈:計劃未來將重心從 CentOS Linux 轉移到 CentOS Stream。CentOS 8 的生命周期已於 2021 年 ...
  • 1. mysql排序問題 一直以為mysql是按照主鍵排序的,實則排序和主鍵沒有關係(不使用 order by 子句)。 然後從 stackoverflow 上查了一下,找到了以下的回答: 沒有預設的排序順序。即使表具有聚集索引,也不能保證按該順序獲得結果。如果需要特定的順序,則必須使用ORDER ...
  • 一、概述 Presto是Facebook開源的MPP(Massively Parallel Processing:大規模並行處理)架構的OLAP(on-line transaction processing:聯機事務處理),完全基於記憶體的並⾏計算,可針對不同數據源,執行大容量數據集的一款分散式SQL ...
  • 書名《MySQL是怎樣運行的:從根兒上理解MySQL》。 這本書講得真的很好,建議大家想學習的去看看😊 本文是基於我的認識上將InnoDB的結構進行的回想,查缺補漏。 InnoDB記錄結構 InnoDB是以頁來存儲數據的,一個頁的大小為16KB。 InnoDB行格式有COMPACT行格式和Redu ...
  • 書名《MySQL是怎樣運行的:從根兒上理解MySQL》可自行百度 以下是知識點總結 重新認識Mysql MySQL是一個C/S架構的軟體。 在Windows安裝後首先註冊成服務,然後會在開機後自啟動。 啟動MySQL服務端。 直接在bin目錄下執行mysqld 或者在配置文件my.ini中設置一些默 ...
  • 導讀: 電商場景的搜索排序演算法根據用戶搜索請求,經過召回、粗排、精排、重排與混排等模塊將最終的結果呈現給用戶,演算法的優化目標是提升用戶轉化。傳統的有監督訓練方式,每一步迭代的過程中優化當前排序結果的即時反饋收益。但是,實際上用戶和搜索系統之間不斷交互,用戶狀態也在不斷變化,每一次交互後排序結果和用戶 ...
  • 查看PostgreSQL鎖表信息 一、查詢PG_STAT_ACTIVITY的信息 SELECT * FROM pg_stat_activity where datname='bms' and wait_event_type='Lock' 二、通過pid解鎖死鎖信息 select pg_cancel_ ...
一周排行
    -Advertisement-
    Play Games
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...