在資料函式庫的世界裡,條件邏輯就像魔法棒一樣,能讓你的 SQL 查詢更靈活、更有效率。Snowflake SQL 提供了 CASE 表示式和 IFF 函式這兩個強大的工具,讓你輕鬆駕馭各種條件判斷。CASE 表示式就像瑞士刀,能處理各種複雜的多條件判斷,而 IFF 函式則像一把鋒利的匕首,專門處理簡單的 if-then-else 邏輯。

CASE 表示式在處理多條件判斷時非常有用,例如根據訂單金額將客戶分類別、根據條件更新或刪除資料。它允許你根據不同的條件傳回不同的結果,讓你的 SQL 查詢更具彈性。而 IFF 函式則適用於簡單的單條件判斷,它能讓你的程式碼更簡潔易懂。透過 IFF 函式,你可以用更少的程式碼完成相同的任務,提升程式碼的可讀性和維護性。這兩個函式都能有效地處理 NULL 值,避免程式出錯或產生不正確的結果。熟練運用 CASEIFF 函式,能讓你寫出更精簡、更有效率的 SQL 查詢,提升資料函式庫效能,讓你事半功倍。

SQL條件邏輯:CASE表示式與IFF()函式的應用

在資料倉管理中,條件邏輯是不可或缺的一環。透過條件邏輯,我們可以根據不同的條件,執行不同的操作或傳回不同的結果。在 Snowflake SQL 中,CASE表示式和IFF()函式是實作條件邏輯的兩個重要工具。玄貓將會探討這兩個工具的應用場景和使用方法。

CASE表示式:多條件判斷的利器

CASE表示式允許我們根據多個條件進行判斷,並傳回不同的結果。它非常適合處理複雜的條件邏輯。

根據訂單金額判斷客戶型別

假設我們想要根據客戶的訂單金額,將客戶分為「大戶 (Big Spender)」和「一般客戶 (Regular)」兩種型別。可以使用以下的 SQL 語法來實作:

SELECT 
    c_custkey, 
    c_name,
    CASE
        WHEN EXISTS (
            SELECT 1 
            FROM orders o
            WHERE o.o_custkey = c.c_custkey
            AND o.o_totalprice > 400000
        ) THEN 'Big Spender'
        ELSE 'Regular'
    END AS cust_type
FROM customer c
WHERE c_custkey BETWEEN 74000 AND 74020;

程式碼解密

  1. SELECT c_custkey, c_name: 選擇客戶的鍵和名稱。
  2. CASE WHEN EXISTS (...) THEN 'Big Spender' ELSE 'Regular' END AS cust_type: 使用CASE表示式判斷客戶型別。如果客戶存在至少一筆訂單金額超過 400000,則為「大戶」,否則為「一般客戶」。
  3. FROM customer c: 從customer表查詢資料。
  4. WHERE c_custkey BETWEEN 74000 AND 74020: 篩選客戶鍵在 74000 到 74020 之間的客戶。

這段程式碼會根據orders表中是否存在總價 (o_totalprice) 超過 400,000 的訂單來判斷客戶型別。如果子查詢傳回至少一筆資料,EXISTS 運算元就會評估為真 (true),CASE表示式就會將客戶標記為「大戶 (Big Spender)」,否則標記為「一般客戶 (Regular)」。

執行上述 SQL 語法後,可能會得到類別似以下的結果:

+-----------+--------------------+-------------+
| C_CUSTKEY | C_NAME             | CUST_TYPE   |
|-----------+--------------------+-------------|
| 74003     | Customer#000074003 | Big Spender |
| 74008     | Customer#000074008 | Regular     |
| 74011     | Customer#000074011 | Big Spender |
| 74014     | Customer#000074014 | Regular     |
| 74015     | Customer#000074015 | Regular     |
| 74000     | Customer#000074000 | Regular     |
| 74009     | Customer#000074009 | Regular     |
| 74020     | Customer#000074020 | Regular     |
| 74017     | Customer#000074017 | Regular     |
| 74012     | Customer#000074012 | Regular     |
| 74005     | Customer#000074005 | Regular     |
+-----------+--------------------+-------------+

條件更新:使用CASE表示式更新客戶型別

除了在查詢中使用CASE表示式外,我們還可以在更新語法中使用它。假設我們想要將customer表中的cust_type欄位,根據客戶的訂單金額進行更新,可以使用以下的 SQL 語法:

UPDATE customer AS c
SET cust_type =
    CASE
        WHEN EXISTS (
            SELECT 1
            FROM orders AS o
            WHERE o.o_custkey = c.c_custkey
            AND o.o_totalprice > 400000
        ) THEN 'Big Spender'
        ELSE 'Regular'
    END;

程式碼解密

  1. UPDATE customer AS c: 更新customer表,並給予別名c
  2. SET cust_type = CASE ... END: 設定cust_type欄位的值,根據CASE表示式判斷。
  3. WHEN EXISTS (...) THEN 'Big Spender': 如果子查詢傳回至少一筆資料,表示客戶為「大戶」。
  4. ELSE 'Regular': 否則,客戶為「一般客戶」。

條件刪除:使用CASE表示式刪除客戶

CASE表示式也可以用於刪除語法中。例如,我們想要刪除所有沒有下過超過 1000 元訂單,或者 1996 年以後沒有下過任何訂單的客戶,可以使用以下的 SQL 語法:

DELETE FROM customer c
WHERE 1 =
    CASE
        WHEN NOT EXISTS (
            SELECT 1
            FROM orders AS o
            WHERE o.o_custkey = c.c_custkey
            AND o.o_totalprice > 1000
        ) THEN 1
        WHEN '1995-12-31' > (
            SELECT MAX(o_orderdate)
            FROM orders AS o
            WHERE o.o_custkey = c.c_custkey
        ) THEN 1
        ELSE 0
    END;

程式碼解密

  1. DELETE FROM customer c: 從customer表刪除資料,並給予別名c
  2. WHERE 1 = CASE ... END: 根據CASE表示式的結果判斷是否刪除客戶。
  3. WHEN NOT EXISTS (...) THEN 1: 如果客戶沒有下過超過 1000 元的訂單,則傳回 1。
  4. WHEN '1995-12-31' > (...) THEN 1: 如果客戶在 1996 年以後沒有下過任何訂單,則傳回 1。
  5. ELSE 0: 否則傳回 0,不刪除客戶。

這段程式碼首先檢查客戶是否曾經下過超過 1000 元的訂單。如果沒有,NOT EXISTS 條件成立,CASE表示式傳回 1,客戶將被刪除。接下來,程式碼檢查客戶是否在 1996 年或之後下過任何訂單。如果沒有,CASE表示式同樣傳回 1,客戶也會被刪除。

IFF()函式:簡潔的單條件判斷

如果只需要一個簡單的 if-then-else 表示式,可以使用IFF()函式。IFF()函式接受三個引數:一個條件表示式,一個如果條件為真的傳回值,以及一個如果條件為假的傳回值。

使用IFF()函式判斷客戶型別

以下範例使用IFF()函式來判斷客戶型別,並且使用CASE表示式的結果進行比較:

SELECT
    c_custkey,
    c_name,
    CASE
        WHEN EXISTS (
            SELECT 1
            FROM orders o
            WHERE o.o_custkey = c.c_custkey
            AND o.o_totalprice > 400000
        ) THEN 'Big Spender'
        ELSE 'Regular'
    END AS cust_type_case,
    IFF(
        EXISTS (
            SELECT 1
            FROM orders o
            WHERE o.o_custkey = c.c_custkey
            AND o.o_totalprice > 400000
        ),
        'Big Spender',
        'Regular'
    ) AS cust_type_iff
FROM customer c
WHERE c_custkey BETWEEN 74000 AND 74020;

程式碼解密

  1. SELECT c_custkey, c_name: 選擇客戶的鍵和名稱。
  2. CASE ... END AS cust_type_case: 使用CASE表示式判斷客戶型別,與先前的範例相同。
  3. IFF(..., 'Big Spender', 'Regular') AS cust_type_iff: 使用IFF()函式判斷客戶型別。如果EXISTS條件成立,則為「大戶」,否則為「一般客戶」。
  4. FROM customer c: 從customer表查詢資料。
  5. WHERE c_custkey BETWEEN 74000 AND 74020: 篩選客戶鍵在 74000 到 74020 之間的客戶。

執行上述 SQL 語法後,可能會得到類別似以下的結果:

+-----------+--------------------+----------------+--------------+
| C_CUSTKEY | C_NAME             | CUST_TYPE_CASE | CUST_TYPE_IFF|
|-----------+--------------------+----------------+--------------|
| 74011     | Customer#000074011 | Big Spender    | Big Spender  |
| 74003     | Customer#000074003 | Big Spender    | Big Spender  |
| 74005     | Customer#000074005 | Regular        | Regular      |
| 74015     | Customer#000074015 | Regular        | Regular      |
| 74017     | Customer#000074017 | Regular        | Regular      |
| 74008     | Customer#000074008 | Regular        | Regular      |
| 74020     | Customer#000074020 | Regular        | Regular      |
| 74000     | Customer#000074000 | Regular        | Regular      |
| 74012     | Customer#000074012 | Regular        | Regular      |
| 74009     | Customer#000074009 | Regular        | Regular      |
| 74014     | Customer#000074014 | Regular        | Regular      |
+-----------+--------------------+----------------+--------------+

從結果中可以看出,CASE表示式和IFF()函式的結果是一致的。

條件邏輯的靈活運用:解鎖 SQL 的更多可能性

在資料函式庫操作中,條件邏輯不僅能提升程式碼的靈活性,還能讓你以更少的程式碼完成更多工。玄貓將帶你深入探索 SQL 中條件邏輯的應用,包括 ifnull()nvl()coalesce()decode() 函式,並分享如何在實際場景中運用它們。

ifnull()nvl():處理遺失值的利器

在處理資料時,遺失值(NULL)是個常見的問題。ifnull()nvl() 函式能讓你輕鬆地用預設值替換 NULL 值,從而避免程式出錯或產生不正確的結果。

以下範例展示如何使用 ifnull()nvl() 函式,將 favorite_color 欄位中的 NULL 值替換為 ‘Unknown’:

PUBLIC> SELECT
    name,
    nvl(favorite_color, 'Unknown') AS favorite_color_nvl,
    ifnull(favorite_color, 'Unknown') AS favorite_color_isnull
FROM
    (
        VALUES
            ('Thomas', 'yellow'),
            ('Catherine', 'red'),
            ('Richard', 'blue'),
            ('Rebecca', NULL)
    ) AS person (name, favorite_color);

這個技巧在報表製作中特別有用,能確保報表呈現完整與易於理解的資訊。

雙重來源取值:ifnull()nvl() 的進階應用

有時,欄位的值可能來自不同的資料表。這時,ifnull()nvl() 函式就能派上用場,讓你從多個來源中選取非 NULL 的值。

考慮以下使用 FULL OUTER JOIN 的例子:

PUBLIC> SELECT
    orders.ordernum,
    CASE
        WHEN orders.custkey IS NOT NULL THEN orders.custkey
        WHEN customer.custkey IS NOT NULL THEN customer.custkey
    END AS custkey_case,
    nvl(orders.custkey, customer.custkey) AS custkey_nvl,
    ifnull(orders.custkey, customer.custkey) AS custkey_ifnull,
    customer.custname AS name
FROM
    (
        VALUES
            (990, 101),
            (991, 102),
            (992, 101),
            (993, 104)
    ) AS orders (ordernum, custkey)
    FULL OUTER JOIN (
        VALUES
            (101, 'BOB'),
            (102, 'KIM'),
            (103, 'JIM')
    ) AS customer (custkey, custname) ON orders.custkey = customer.custkey;

在這個例子中,custkey 的值可能來自 orderscustomer 資料表。透過 nvl()ifnull() 函式,我們可以確保選取到非 NULL 的 custkey 值。

coalesce():多重選擇的終極方案

當需要在多個欄位中尋找非 NULL 值時,coalesce() 函式是你的最佳選擇。它可以接受任意數量的表示式,並傳回第一個非 NULL 的值。

-- 範例:從三個欄位中選取第一個非 NULL 值
SELECT
    coalesce(column1, column2, column3) AS first_non_null
FROM
    your_table;

decode():簡潔的條件判斷

decode() 函式類別似於簡單的 CASE 表示式,它將一個表示式與一系列值進行比較,並在找到比對項時傳回相應的值。

以下範例展示如何使用 decode() 函式,將 o_orderstatus 欄位的值轉換為易於理解的狀態描述:

PUBLIC> SELECT
    o_orderkey,
    CASE
        o_orderstatus
        WHEN 'P' THEN 'Partial'
        WHEN 'F' THEN 'Filled'
        WHEN 'O' THEN 'Open'
    END AS status_case,
    decode(
        o_orderstatus,
        'P',
        'Partial',
        'F',
        'Filled',
        'O',
        'Open'
    ) AS status_decode
FROM
    orders
LIMIT
    20;

雖然 decode() 函式更簡潔,但玄貓更推薦使用 CASE 表示式,因為它更易於理解,與在不同的資料函式庫伺服器之間具有更好的移植性。

測驗你的知識

以下練習旨在測試你對條件邏輯的理解程度。

練習 10-1

在以下查詢中新增一個名為 order_status 的欄位,使用 CASE 表示式根據 ps_availqty 的值傳回不同的結果:

  • ps_availqty 小於 100,傳回 ‘order now’
  • ps_availqty 介於 101 和 1000 之間,傳回 ‘order soon’
  • 否則,傳回 ‘plenty in stock’
PUBLIC> SELECT
    ps_partkey,
    ps_suppkey,
    ps_availqty
FROM
    partsupp
WHERE
    ps_partkey BETWEEN 148300 AND 148450;

練習 10-2

將以下查詢改寫為使用 searched CASE 表示式,而不是 simple CASE 表示式:

PUBLIC> SELECT
    o_orderdate,
    o_custkey,
    CASE
        o_orderstatus
        WHEN 'P' THEN 'Partial'
        WHEN 'F' THEN 'Filled'
        WHEN 'O' THEN 'Open'
    END status
FROM
    orders
WHERE
    o_orderkey > 5999500;

練習 10-3

以下查詢傳回每個地區的供應商數量:

PUBLIC> SELECT
    r_name,
    count(*)
FROM
    nation n
    INNER JOIN region r ON r.r_regionkey = n.n_regionkey
    INNER JOIN supplier s ON s.s_nationkey = n.n_nationkey
GROUP BY
    r_name;

修改此查詢,使用 CASE 表示式將資料透視成以下格式:

+---------+--------+--------+-------------+------+
| AMERICA | AFRICA | EUROPE | MIDDLE_EAST | ASIA |
+---------+--------+--------+-------------+------+
| 1532    | 1444   | 1474   | 1491        | 1459 |
+---------+--------+--------+-------------+------+