什麼是 SQL CASE 表達式,如何使用 SQL CASE 表達式

来源:https://www.cnblogs.com/vin-c/archive/2022/06/14/16373962.html
-Advertisement-
Play Games

本文介紹 SQL CASE 表達式,它是 SQL 中數一數二的重要功能,CASE 表達式的語法分為簡單 CASE 表達式和搜索 CASE 表達式兩種。 本文重點 CASE 表達式分為簡單 CASE 表達式和搜索 CASE 表達式兩種。搜索 CASE 表達式包含簡單 CASE 表達式的全部功能。 雖然 ...


目錄

本文介紹 SQL CASE 表達式,它是 SQL 中數一數二的重要功能,CASE 表達式的語法分為簡單 CASE 表達式搜索 CASE 表達式兩種。

本文重點

  • CASE 表達式分為簡單 CASE 表達式和搜索 CASE 表達式兩種。搜索 CASE 表達式包含簡單 CASE 表達式的全部功能。

  • 雖然 CASE 表達式中的 ELSE 子句可以省略,但為了讓 SQL 語句更加容易理解,還是希望大家不要省略。

  • CASE 表達式中的 END 不能省略。

  • 使用 CASE 表達式能夠將 SELECT 語句的結果進行組合。

  • 雖然有些 DBMS 提供了各自特有的 CASE 表達式的簡化函數,例如 Oracle 中的 DECODE 和 MySQL 中的 IF,等等,但由於它們並非通用的函數,功能上也有些限制,因此有些場合無法使用。

一、什麼是 CASE 表達式

本文將要學習的 CASE 表達式,和“1 + 1”或者“120 / 4”這樣的表達式一樣,是一種進行運算的功能。這就意味著 CASE 表達式也是函數的一種。

它是 SQL 中數一數二的重要功能,希望大家能夠在這裡好好學習掌握。

CASE 表達式是在區分情況時使用的,這種情況的區分在編程中通常稱為 (條件)分支 [1]

二、CASE 表達式的語法

CASE 表達式的語法分為簡單 CASE 表達式搜索 CASE 表達式兩種。但是,由於搜索 CASE 表達式包含了簡單 CASE 表達式的全部功能,因此本文只會介紹搜索 CASE 表達式。

想要瞭解簡單 CASE 表達式語法的讀者,可以參考本文末尾的“簡單 CASE 表達式”專欄。

下麵就讓我們趕快來學習一下搜索 CASE 表達式的語法吧。

語法 16 搜索 CASE 表達式

CASE WHEN <求值表達式> THEN <表達式>
     WHEN <求值表達式> THEN <表達式>
     WHEN <求值表達式> THEN <表達式>
       .
       .
       .
     ELSE <表達式>
END

WHEN 子句中的“<求值表達式>”就是類似“列 = 值”這樣,返回值為真值(TRUE/FALSE/UNKNOWN)的表達式。

我們也可以將其看作使用 =!= 或者 LIKEBETWEEN謂詞 編寫出來的表達式。

CASE 表達式會從對最初的 WHEN 子句中的“<求值表達式>”進行求值開始執行。

所謂求值,就是要調查該表達式的真值是什麼。如果結果為真(TRUE),那麼就返回 THEN 子句中的表達式,CASE 表達式的執行到此為止。

如果結果不為真,那麼就跳轉到下一條 WHEN 子句的求值之中。如果直到最後的 WHEN 子句為止返回結果都不為真,那麼就會返回 ELSE 中的表達式,執行終止。

CASE 表達式名稱中的“表達式”我們也能看出來,上述這些整體構成了一個表達式。並且由於表達式最終會返回一個值,因此 CASE 表達式在 SQL 語句執行時,也會轉化為一個值。

雖然使用分支眾多的 CASE 表達式編寫幾十行代碼的情況也並不少見,但是無論多麼龐大的 CASE 表達式,最後也只會返回類似“1”或者“'渡邊先生'”這樣簡單的值。

三、CASE 表達式的使用方法

那麼就讓我們來學習一下 CASE 表達式的具體使用方法吧。

例如我們來考慮這樣一種情況,現在 Product(商品)表中包含衣服、辦公用品和廚房用具 3 種商品類型,請大家考慮一下怎樣才能夠得到如下結果。

A :衣服
B :辦公用品
C :廚房用具

因為表中的記錄並不包含“A :”或者“B :”這樣的字元串,所以需要在 SQL 中進行添加。我們可以使用 SQL 常用的函數 中學過的字元串連接函數“||”來完成這項工作。

剩下的問題就是怎樣正確地將“A :”“B :”“C :”與記錄結合起來。這時就可以使用 CASE 表達式來實現了(代碼清單 41)。

代碼清單 41 通過 CASE 表達式將 A ~ C 的字元串加入到商品種類當中

SELECT product_name,
       CASE WHEN product_type = '衣服'
            THEN 'A:' || product_type
            WHEN product_type = '辦公用品'
            THEN 'B:' || product_type
            WHEN product_type = '廚房用具'
            THEN 'C:' || product_type
            ELSE NULL
       END AS abc_product_type
  FROM Product;

執行結果:

 product_name | abc_product_type
--------------+------------------
 T恤衫        | A :衣服
 打孔器       | B :辦公用品
 運動T恤      | A :衣服
 菜刀         | C :廚房用具
 高壓鍋       | C :廚房用具
 叉子         | C :廚房用具
 擦菜板       | C :廚房用具
 圓珠筆       | B :辦公用品

6 行 CASE 表達式代碼最後只相當於 1 列(abc_product_type)而已,大家也許有點吃驚吧!與商品種類(product_type)的名稱相對應,CASE 表達式中包含了 3 條 WHEN 子句分支。

最後的 ELSE NULL 是“上述情況之外時返回 NULL”的意思。

ELSE 子句指定了應該如何處理不滿足 WHEN 子句中的條件的記錄,NULL 之外的其他值或者表達式也都可以寫在 ELSE 子句之中。

但由於現在表中包含的商品種類只有 3 種,因此實際上有沒有 ELSE 子句都是一樣的。

ELSE 子句也可以省略不寫,這時會被預設為 ELSE NULL。但為了防止有人漏讀,還是希望大家能夠顯式地寫出 ELSE 子句。

法則 3

雖然 CASE 表達式中的 ELSE 子句可以省略,但還是希望大家不要省略。

此外,CASE 表達式最後的“END”是不能省略的,請大家特別註意不要遺漏。忘記書寫 END 會發生語法錯誤,這也是初學時最容易犯的錯誤。

法則 4

CASE 表達式中的 END 不能省略。

四、CASE 表達式的書寫位置

CASE 表達式的便利之處就在於它是一個表達式。

之所以這麼說,是因為表達式可以書寫在任意位置,也就是像“1 + 1”這樣寫在什麼位置都可以的意思。

例如,我們可以像下麵這樣利用 CASE 表達式將 SELECT 語句的結果中的行和列進行互換。

執行結果:

sum_price_clothes | sum_price_kitchen | sum_price_office
------------------+-------------------+-----------------
             5000 |             11180 |              600

上述結果是根據商品種類計算出的銷售單價的合計值,通常我們將商品種類列作為 GROUP BY 子句的聚合鍵來使用,但是這樣得到的結果會以“行”的形式輸出,而無法以列的形式進行排列(代碼清單 42)。

代碼清單 42 通常使用 GROUP BY 也無法實現行列轉換

SELECT product_type,
       SUM(sale_price) AS sum_price
  FROM Product
 GROUP BY product_type;

執行結果:

 product_type | sum_price
--------------+----------
 衣服         |      5000
 辦公用品     |       600
 廚房用具     |     11180

我們可以像代碼清單 43 那樣在 SUM 函數中使用 CASE 表達式來獲得一個 3 列的結果。

代碼清單 43 使用 CASE 表達式進行行列轉換

-- 對按照商品種類計算出的銷售單價合計值進行行列轉換
SELECT SUM(CASE WHEN product_type = '衣服'
                THEN sale_price ELSE 0 END) AS sum_price_clothes,
       SUM(CASE WHEN product_type = '廚房用具'
                THEN sale_price ELSE 0 END) AS sum_price_kitchen,
       SUM(CASE WHEN product_type = '辦公用品'
                THEN sale_price ELSE 0 END) AS sum_price_office
  FROM Product;

在滿足商品種類(product_type)為“衣服”或者“辦公用品”等特定值時,上述 CASE 表達式輸出該商品的銷售單價(sale_price),不滿足時輸出 0

對該結果進行彙總處理,就能夠得到特定商品種類的銷售單價合計值了。

在對 SELECT 語句的結果進行編輯時,CASE 表達式能夠發揮較大作用。

專欄

簡單 CASE 表達式

CASE 表達式分為兩種,一種是本文學習的“搜索 CASE 表達式”,另一種就是其簡化形式——“簡單 CASE 表達式”。

簡單 CASE 表達式比搜索 CASE 表達式簡單,但是會受到條件的約束,因此通常情況下都會使用搜索 CASE 表達式。在此我們簡單介紹一下其語法結構。

簡單 CASE 表達式的語法如下所示。

語法 A 簡單 CASE 表達式

CASE <表達式>
   WHEN <表達式> THEN <表達式>
   WHEN <表達式> THEN <表達式>
   WHEN <表達式> THEN <表達式>
       .
       .
       .
   ELSE <表達式>
END

與搜索 CASE 表達式一樣,簡單 CASE 表達式也是從最初的 WHEN 子句開始進行,逐一判斷每個 WHEN 子句直到返回真值為止。

此外,沒有能夠返回真值的 WHEN 子句時,也會返回 ELSE 子句指定的表達式。兩者的不同之處在於,簡單 CASE 表達式最初的“CASE<表達式>”也會作為求值的對象。

下麵就讓我們來看一看搜索 CASE 表達式和簡單 CASE 表達式是如何實現相同含義的 SQL 語句的。

將代碼清單 41 中的搜索 CASE 表達式的 SQL 改寫為簡單 CASE 表達式,結果如下所示(代碼清單 A)。

代碼清單 A 使用 CASE 表達式將字元串 A ~ C 添加到商品種類中

-- 使用搜索CASE表達式的情況(重寫代碼清單6-41)
SELECT product_name,
     CASE WHEN product_type = '衣服'
          THEN 'A :' | |product_type
          WHEN product_type = '辦公用品'
          THEN 'B :' | |product_type
          WHEN product_type = '廚房用具'
          THEN 'C :' | |product_type
          ELSE NULL
      END AS abc_product_type
 FROM Product;


-- 使用簡單CASE表達式的情況
SELECT product_name,
      CASE product_type
           WHEN '衣服'      THEN 'A :' || product_type
           WHEN '辦公用品'  THEN 'B :' || product_type
           WHEN '廚房用具'  THEN 'C :' || product_type
           ELSE NULL
       END AS abc_product_type
 FROM Product;

像“CASE product_type”這樣,簡單 CASE 表達式在將想要求值的表達式(這裡是列)書寫過一次之後,就無需在之後的 WHEN 子句中重覆書寫“product_type”了。

雖然看上去簡化了書寫,但是想要在 WHEN 子句中指定不同列時,簡單 CASE 表達式就無能為力了。

專欄

特定的 CASE 表達式

由於 CASE 表達式是標準 SQL 所承認的功能,因此在任何 DBMS 中都可以執行。

但是,有些 DBMS 還提供了一些特有的 CASE 表達式的簡化函數,例如 Oracle 中的 DECODE、MySQL 中的 IF 等。

使用 Oracle 中的 DECODE 和 MySQL 中的 IF 將字元串 A ~ C 添加到商品種類(product_type)中的 SQL 語句請參考代碼清單 B。

代碼清單 B 使用 CASE 表達式的特定語句將字元串 A ~ C 添加到商品種類中

Oracle

-- Oracle中使用DECODE代替CASE表達式
SELECT  product_name,
      DECODE(product_type,
                 '衣服',      'A :' || product_type,
                 '辦公用品',  'B :' || product_type,
                 '廚房用具',  'C :' || product_type,
             NULL) AS abc_product_type
FROM Product;

MySQL

-- MySQL中使用IF代替CASE表達式
SELECT  product_name,
      IF( IF( IF(product_type = '衣服',
                  CONCAT('A :', product_type), NULL)
              IS NULL AND product_type = '辦公用品',
                  CONCAT('B :', product_type),
          IF(product_type = '衣服',
             CONCAT('A :', product_type), NULL))
                 IS NULL AND product_type = '廚房用具',
                    CONCAT('C :', product_type),
                 IF( IF(product_type = '衣服',
                      CONCAT('A :', product_type), NULL)
              IS NULL AND product_type = '辦公用品',
                 CONCAT('B :', product_type),
          IF(product_type = '衣服',
             CONCAT('A :', product_type),
        NULL))) AS abc_product_type
FROM Product;

但上述函數只能在特定的 DBMS 中使用,並且能夠使用的條件也沒有 CASE 表達式那麼豐富,因此並沒有什麼優勢。希望大家儘量不要使用這些特定的 SQL 語句。

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

(完)


  1. 在 C 語言和 Java 等流行的編程語言中,通常都會使用 IF 語句或者 CASE 語句。CASE 表達式就是這些語句的 SQL 版本。 ↩︎


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

-Advertisement-
Play Games
更多相關文章
  • 在基於SqlSugar的開發框架的服務層中處理文件上傳的時候,我們一般有兩種處理方式,一種是常規的把文件存儲在本地文件系統中,一種是通過FTP方式存儲到指定的FTP伺服器上。這種處理應該由程式進行配置,決定使用那種方式,那麼這裡面我們為了彈性化處理, 在文件上傳模塊中採用選項模式【Options】處... ...
  • public class ZhmSlider : Control { private Rectangle foreRect; private Rectangle backRect; private Rectangle setRect; private Color backgroundColor = ...
  • Pressure Stall Information 壓力失速信息 Date: April, 2018 Author: Johannes Weiner [email protected] 當CPU、MEM或者IO設備被爭奪時,工作負載就會經受延遲增加,吞吐量損失和運行時被OOM殺死的風險。 如果沒 ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 安裝前準備 一、可以考慮替換國內yum鏡像 根據我老中醫多年的經驗,需要從某些倉庫啊之類的下載某些包的時候,最好先看看怎麼替換國內的鏡像(否則下載會非常慢,更拉的時候還會缺這少那導致最後項目報莫名其妙地報錯);so,yum的鏡像源替換可以參考:y ...
  • 下載軟體以及選擇適合的Linux系統 VMware Workstation 下載地址: 下載 VMware Workstation Pro | CN 阿裡巴巴鏡像源地址:OPSX鏡像站 配置Linux系統 點擊創建新的虛擬機 選擇自定義 ———>下一步 ———> 下一步 選擇稍後安裝操作系統 ——— ...
  • 一、package的作用 • Oracle中包的概念與Java中包的概念非常類似,只是Java中的包是為了分類管理類,但是關鍵字都是package。 • 在一個大型項目中,可能有很多模塊,而每個模塊又有自己的過程、函數等。而這些過程、函數預設是放在一起的(如在PL/SQL中,過程預設都是放在一起的, ...
  • 導語 在使用xtrabackup8版本對mysql8版本進行備份恢復搭建從庫的時候,繼續使用xtrabackup2版本的方式,從xtrabackup_binlog_info 文件中找到gtid信息,執行purge,嘗試多次發現搭建失敗,於是對xtrabackup2和xtrbackup8版本備份流程( ...
  • 導讀: 首先簡單介紹一下網易杭州研究院情況簡介,如下圖所示: 我們公司主要從事平臺技術開發和建設方面,工作的重點方向主要在解決用戶在數據治理中的各種問題,讓用戶能更高效地管理自己的數據,進而產生更大的價值,比如如何整合現有功能流程,節省用戶使用成本;增加新平臺不斷調研,豐富平臺功能;新平臺功能、性能 ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...