什麼是 SQL 子查詢,如何使用 SQL 子查詢

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

本文介紹什麼是 SQL 子查詢,如何使用它們。子查詢常用於 WHERE 子句的 IN 操作符中,以及用來填充計算列。 一、子查詢 SELECT 語句是 SQL 的查詢。我們迄今為止所看到的所有 SELECT 語句都是簡單查詢,即從單個資料庫表中檢索數據的單條語句。 查詢(query) 任何 SQL ...


目錄

本文介紹什麼是 SQL 子查詢,如何使用它們。子查詢常用於 WHERE 子句的 IN 操作符中,以及用來填充計算列。

一、子查詢

SELECT 語句是 SQL 的查詢。我們迄今為止所看到的所有 SELECT 語句都是簡單查詢,即從單個資料庫表中檢索數據的單條語句。

查詢(query)

任何 SQL 語句都是查詢。但此術語一般指 SELECT 語句。

SQL 還允許創建子查詢(subquery),即嵌套在其他查詢中的查詢。為什麼要這樣做呢?理解這個概念的最好方法是考察幾個例子。

二、利用子查詢進行過濾

訂單存儲在兩個表中。每個訂單包含訂單編號、客戶 ID、訂單日期,在 Orders 表中存儲為一行。各訂單的物品存儲在相關的 OrderItems 表中。Orders 表不存儲顧客信息,只存儲顧客 ID。顧客的實際信息存儲在 Customers 表中。

現在,假如需要列出訂購物品 RGAN01 的所有顧客,應該怎樣檢索?下麵列出具體的步驟。

(1) 檢索包含物品 RGAN01 的所有訂單的編號。

(2) 檢索具有前一步驟列出的訂單編號的所有顧客的 ID

(3) 檢索前一步驟返回的所有顧客 ID 的顧客信息。

上述每個步驟都可以單獨作為一個查詢來執行。可以把一條 SELECT 語句返回的結果用於另一條 SELECT 語句的 WHERE 子句。

也可以使用子查詢來把 3 個查詢組合成一條語句。

第一條 SELECT 語句的含義很明確,它對 prod_idRGAN01 的所有訂單物品,檢索其 order_num 列。輸出列出了兩個包含此物品的訂單:

SELECT order_num
FROM OrderItems
WHERE prod_id = 'RGAN01';

輸出:

order_num
-----------
20007
20008

現在,我們知道了哪個訂單包含要檢索的物品,下一步查詢與訂單 2000720008 相關的顧客 ID。利用 如何使用 SQL AND、OR、IN 和 NOT 過濾返回的數據 介紹的 IN 子句,編寫如下的 SELECT 語句:

SELECT cust_id
FROM Orders
WHERE order_num IN (20007,20008);

輸出:

cust_id
----------
1000000004
1000000005

現在,結合這兩個查詢,把第一個查詢(返回訂單號的那一個)變為子查詢。請看下麵的 SELECT 語句:

SELECT cust_id
FROM Orders
WHERE order_num IN (SELECT order_num
                    FROM OrderItems
                    WHERE prod_id = 'RGAN01');

輸出:

cust_id
----------
1000000004
1000000005

SELECT 語句中,子查詢總是從內向外處理。在處理上面的 SELECT 語句時,DBMS 實際上執行了兩個操作。

首先,它執行下麵的查詢:

SELECT order_num FROM orderitems WHERE prod_id='RGAN01'

此查詢返回兩個訂單號:2000720008。然後,這兩個值以 IN 操作符要求的逗號分隔的格式傳遞給外部查詢的 WHERE 子句。外部查詢變成:

SELECT cust_id FROM orders WHERE order_num IN (20007,20008)

可以看到,輸出是正確的,與前面硬編碼 WHERE 子句所返回的值相同。

提示:格式化 SQL

包含子查詢的 SELECT 語句難以閱讀和調試,它們在較為複雜時更是如此。如上所示,把子查詢分解為多行併進行適當的縮進,能極大地簡化子查詢的使用。

順便一提,這就是顏色編碼起作用的地方,好的 DBMS 客戶端正是出於這個原因使用了顏色代碼 SQL。

現在得到了訂購物品 RGAN01 的所有顧客的 ID。下一步是檢索這些顧客 ID 的顧客信息。檢索兩列的 SQL 語句為:

SELECT cust_name, cust_contact
FROM Customers
WHERE cust_id IN (1000000004,1000000005);

可以把其中的 WHERE 子句轉換為子查詢,而不是硬編碼這些顧客 ID

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'));

輸出:

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

為了執行上述 SELECT 語句,DBMS 實際上必須執行三條 SELECT 語句。最裡邊的子查詢返回訂單號列表,此列表用於其外面的子查詢的 WHERE 子句。

外面的子查詢返回顧客 ID 列表,此顧客 ID 列表用於最外層查詢的 WHERE 子句。最外層查詢返回所需的數據。

可見,在 WHERE 子句中使用子查詢能夠編寫出功能很強且很靈活的 SQL 語句。對於能嵌套的子查詢的數目沒有限制,不過在實際使用時由於性能的限制,不能嵌套太多的子查詢。

註意:只能是單列

作為子查詢的 SELECT 語句只能查詢單個列。企圖檢索多個列將返回錯誤。

註意:子查詢和性能

這裡給出的代碼有效,並且獲得了所需的結果。但是,使用子查詢並不總是執行這類數據檢索的最有效方法。更多的論述,請參閱 如何使用 SQL INNER JOIN 聯結兩個或多個表,其中將再次給出這個例子。

三、作為計算欄位使用子查詢

使用子查詢的另一方法是創建計算欄位。假如需要顯示 Customers 表中每個顧客的訂單總數。訂單與相應的顧客 ID 存儲在 Orders 表中。

執行這個操作,要遵循下麵的步驟:

(1) 從 Customers 表中檢索顧客列表;

(2) 對於檢索出的每個顧客,統計其在 Orders 表中的訂單數目。

正如前兩課所述,可以使用 SELECT COUNT(*) 對錶中的行進行計數,並且通過提供一條 WHERE 子句來過濾某個特定的顧客 ID,僅對該顧客的訂單進行計數。

例如,下麵的代碼對顧客 1000000001 的訂單進行計數:

SELECT COUNT(*) AS orders
FROM Orders
WHERE cust_id = 1000000001;

要對每個顧客執行 COUNT(*),應該將它作為一個子查詢。請看下麵的代碼:

SELECT cust_name,
       cust_state,
       (SELECT COUNT(*)
        FROM Orders
        WHERE Orders.cust_id = Customers.cust_id) AS orders
FROM Customers
ORDER BY cust_name;

輸出:

cust_name                     cust_state     orders
-------------------------     ----------     ------
Fun4All                       IN             1
Fun4All                       AZ             1
Kids Place                    OH             0
The Toy Store                 IL             1
Village Toys                  MI             2

這條 SELECT 語句對 Customers 表中每個顧客返回三列:cust_namecust_stateorders

orders 是一個計算欄位,它是由圓括弧中的子查詢建立的。該子查詢對檢索出的每個顧客執行一次。在此例中,該子查詢執行了 5 次,因為檢索出了 5 個顧客。

子查詢中的 WHERE 子句與前面使用的 WHERE 子句稍有不同,因為它使用了完全限定列名,而不只是列名(cust_id)。它指定表名和列名(Orders.cust_idCustomers.cust_id)。

下麵的 WHERE 子句告訴 SQL,比較 Orders 表中的 cust_id 和當前正從 Customers 表中檢索的 cust_id

WHERE Orders.cust_id = Customers.cust_id

用一個句點分隔表名和列名,在有可能混淆列名時必須使用這種語法。在這個例子中,有兩個 cust_id 列:一個在 Customers 中,另一個在 Orders 中。如果不採用完全限定列名,DBMS 會認為要對 Orders 表中的 cust_id 自身進行比較。因為

SELECT COUNT(*) FROM Orders WHERE cust_id = cust_id

總是返回 Orders 表中訂單的總數,而這個結果不是我們想要的:

SELECT cust_name,
       cust_state,
       (SELECT COUNT(*)
        FROM Orders
        WHERE cust_id = cust_id) AS orders
FROM Customers
ORDER BY cust_name;

輸出:

cust_name                     cust_state     orders
-------------------------     ----------     ------
Fun4All                       IN             5
Fun4All                       AZ             5
Kids Place                    OH             5
The Toy Store                 IL             5
Village Toys                  MI             5

雖然子查詢在構造這種 SELECT 語句時極有用,但必須註意限制有歧義的列。

註意:完全限定列名

你已經看到了為什麼要使用完全限定列名,沒有具體指定就會返回錯誤結果,因為 DBMS 會誤解你的意思。

有時候,由於出現衝突列名而導致的歧義性,會引起 DBMS 拋出錯誤信息。

例如,WHEREORDER BY 子句指定的某個列名可能會出現在多個表中。

好的做法是,如果在 SELECT 語句中操作多個表,就應使用完全限定列名來避免歧義。

提示:不止一種解決方案

正如本文前面所述,雖然這裡給出的樣例代碼運行良好,但它並不是解決這種數據檢索的最有效方法。在 如何使用 SQL INNER JOIN 聯結兩個或多個表SQL 如何使用自聯結、自然聯結和外聯結 學習 JOIN 時,我們還會遇到這個例子。

四、小結

本文介紹了什麼是子查詢,如何使用它們。子查詢常用於 WHERE 子句的 IN 操作符中,以及用來填充計算列。我們舉了這兩種操作類型的例子。

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

(完)


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

-Advertisement-
Play Games
更多相關文章
  • rpm命令 rpm(英文全拼:redhat package manager) 原本是 Red Hat Linux 發行版專門用來管理 Linux 各項套件的程式,由於它遵循 GPL 規則且功能強大方便,因而廣受歡迎。逐漸受到其他發行版的採用。RPM 套件管理方式的出現,讓 Linux 易於安裝,升級 ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 centos換源+安裝postgresql http://mirror.nsc.liu.se/centos-store/8.2.2004/isos/x86_64/ 鏡像安裝網站 https://mirrors.edge.kernel.org/pu ...
  • 本文例子參考《STM32單片機開發實例——基於Proteus虛擬模擬與HAL/LL庫》 源代碼:https://github.com/LanLinnet/STM33F103R6 項目要求 實現通過串口助手發送單位元組數據,單片機收到數據後,交換高4位與低4位,將新的數據通過串口發回串口助手。例如,串口 ...
  • 前言: 這是《VMware 虛擬機圖文安裝和配置 Rocky Linux 8.5 教程》一文的姐妹篇教程,如果你需要閱讀它,請點擊這裡。 2020 年,CentOS 宣佈:計劃未來將重心從 CentOS Linux 轉移到 CentOS Stream。CentOS 8 的生命周期已於 2021 年 ...
  • 一、Azkaban API概述 通常,企業里一般不用使用web UI去設置或者執行任務,只是單純的在頁面上查看任務或者排查問題,更多的是通過Azkaban API去提交執行任務計劃。Azkaban提供了一些常用的API操作,可以通過curl或其他HTTP請求客戶端訪問。但是API調用都需要首先進行適 ...
  • 導讀: 美團是一個生活服務領域的平臺,需要大量知識來理解用戶的搜索意圖,同時對於商家側我們也需要利用現有的知識對海量信息進行挖掘與提取,進而優化用戶體驗。今天分享的主題是知識圖譜在美團推薦場景中的應用。主要包括以下幾方面內容: 美團知識圖譜介紹 美團推薦場景介紹 美團推薦中的知識應用 總結與展望 - ...
  • 大家好,我是大D。 不知是否有小伙伴們疑問,為什麼列式存儲會廣泛地應用在 OLAP 領域,和行式存儲相比,它的優勢在哪裡?今天我們一起來對比下這兩種存儲方式的差別。 其實,列式存儲並不是一項新技術,最早可以追溯到 1983 年的論文 Cantor。然而,受限於早期的硬體條件和應用場景,傳統的事務型數 ...
  • hi,大家好,我是大D。今天咱們繼續深挖一下 HBase 的架構組成。 Hbase 作為 NoSQL 資料庫的代表,屬於三駕馬車之一 BigTable 的對應實現,HBase 的出現很好地彌補了大數據快速查詢能力的空缺。在前面咱們也有介紹過 HBase 的數據模型,感興趣的小伙伴可以翻看下。談談你對 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...