20

20. 認識進階的 T-SQL

INSERT 陳述式

UPDATE 陳述式

DELETE 陳述式

程式設計關鍵字

本章總結

本章將詳細討論前面章節所使用過用來修改資料的T-SQL陳述式，加上一些可用來控制程式設計流程的T-SQL關鍵字。這些陳述式及關鍵字可用於任何可以使用T-SQL的地方，如使用在指令行、指令碼、預存程序、批次檔和應用程式中。我們會特別學習有關資料處理的陳述式，如INSERT、UPDATE和DELETE（這些陳述式在 第十三章 曾經提到過），以及程式結構，如IF、WHILE和CASE。

首先我們為範例建立一個資料表，命名為items（請將該資料表建立在MyDB資料庫內），以下為建立items資料表的T-SQL命令：

    USE MyDB
    GO
    CREATE TABLE items
    (
    item_category   CHAR(20)        NOT NULL,
    item_id         SMALLINT        NOT NULL,
    price           SMALLMONEY      NULL,
    item_desc       VARCHAR(30)     DEFAULT 'No desc'
    )
    GO

item_id資料行適合設成IDENTITY屬性（請參閱 第十章的〈增加IDENTITY屬性〉 。但由於識別資料行不允許直接插入值，因此這裡不使用IDENTITY；這樣才可以更有彈性的使用包含INSERT陳述式的範例。

INSERT陳述式

在

十三章 曾介紹過INSERT陳述式，可以用來新增資料列至資料表或檢視表。以下為INSERT陳述式的基本語法：

    INSERT [INTO] table_name [(column_list)] VALUES
        expression | derived_table

INTO關鍵字和 資料行清單（column_list） 參數可依需要而設定。 資料行清單 參數指定了要插入值的資料行，這些值和運算式中所列的值按順序對應（也可以只包含值的清單）。

插入資料列

下面範例示範如何插入資料列至items資料表。

    INSERT INTO items
        (item_category, item_id, price, item_desc)
    VALUES ('health food', 1, 4.00, 'tofu 6 oz.')
    GO

由於已經替資料表中的每個資料行都指定了一個值，而且依照資料列在資料表中定義的順序列出對應的值，因此我們也可以不必使用 資料行清單 。但是如果值不是依資料行的順序排列，輸入的資料就可能不正確，或是收到錯誤訊息。舉例來說，試著執行以下的陳述式，就會收到錯誤訊息：

    INSERT INTO items
    VALUES (1, 'health food', 4.00, 'tofu 6 oz.')
    GO
    伺服器：訊息245，層級16，狀態1，行1
    將varchar數值 'health food' 轉換成資料型別為smallint的資料行語法錯
    誤。

由於值所放置的順序不正確，因此資料列並沒有被插入，並傳回錯誤訊息。我們嘗試把item_id插入item_category資料行，item_category插入item_id資料行（兩個資料輸入的順序顛倒），兩個不同資料型別的資料並不相容，當然，如果兩個資料行的型別是相容的，就算數值不同，資料也會被插入，不過資料雖然被插入，卻是不正確的資料。

要看看插入的列在資料表中如何顯示，使用下面的SELECT陳述式查詢資料表，以選擇所有的列。

    SELECT * from items
    GO

會看到以下的結果集：

    item_category   item_id price   item_desc
    --------------  -------------   ----------
    health food     1       4.00    tofu 6 oz.

當建立items資料表時，price資料行定義為允許NULL值，item_desc（描述）資料行的預設值為No desc。如果INSERT陳述式中沒有替price資料行指定一個值，新資料列中將插入NULL；如果item_desc資料行沒有指定一個值，將插入預設值No desc。

省略資料行值

在前面INSERT陳述式範例中，由於price資料行和item_desc資料行設有預設值，所以可以省略資料行的值和名稱。如果要省略資料行的值，必須為其他在 資料行清單 的資料行指定參數，否則，列出的值將依照資料表中資料行定義的順序，分配給各資料行。

舉例來說，我們照下面這樣輸入：在 資料行清單 中少輸入了一行價錢，也沒有為 資料行清單 指定值。

    INSERT INTO items
    VALUES ('junk food', 2, 'fried pork skins')
    GO

SQL Server會試著把item_desc（值清單中的第三個值）提供的值（fried pork skins）插入price資料行（資料表中的第三欄位）。由於price資料行為smallmoney資料型別，fried pork skins是char資料型別，兩個不相容的資料型別，就會產生如下的錯誤訊息：

    伺服器：訊息213，層級16，狀態4，行1
    插入錯誤：資料行名稱或提供的數值數量與資料表定義不相符。

試想如果fried pork skins的資料型別和price資料行相容，資料就會被不正確的插入，也影響了整個資料表的一致性與正確性。

記住插入資料表或檢視表的值的資料型別必須和欄位定義的資料型別相容。還有，如果插入的資料列違反了規則或條件約束，會產生錯誤訊息，資料列也不會被插入。

為了避免不相容資料型別的錯誤發生，指定 資料行清單 以符合應當被插入的值，如下所示：

    INSERT INTO items
        (item_category, item_id, item_desc)
    VALUES ('junk food', 2, 'fried pork skins')
    GO

由於沒有指定價格，price資料行將插入NULL值。執行下面的SELECT陳述式：

    SELECT * FROM items

應該會出現下述的結果集，結果集中包含已插入的兩個資料列，注意price資料列中的NULL。

    item_category   item_id price   item_desc
    --------------  --------------  -----------------
    health food     1       4.00    tofu 6 oz.
    junk food       2       NULL    fried pork skins

現在增加另一資料列，不要指定price資料行或item_desc資料行的值，如下所示：

    INSERT INTO items
        (item_category, item_id)
    VALUES ('toy', 3)
    GO

使用下面的查詢就可以得到該列的結果集：

    SELECT * FROM items WHERE item_id = 3

結果集如下所示：

    item_category   item_id price   item_desc
    --------------  --------------  ------------
    toys    3       NULL    No desc

注意price資料行中的NULL和item_desc資料列中的No desc。這些值可用稍後本章將介紹的UPDATE陳述式變更。

有四種類型的資料行，在沒有指定值時，SQL Server會自動提供值給該資料行：分別是 允許NULL值 、 設定預設值 、 IDENTITY屬性 和 時間戳記（timestamp） 的資料行。之前討論過允許NULL值的資料行和含預設值的資料行，若沒有指定值會產生的情形（在 第十章 討論過）。大部分的情況下，是不能手動插入資料值到這兩種類型的資料行中。

說明

在資料表中執行INSERT操作時要謹慎。請確定插入的資料正確地放入應當插入的資料行。確定測試了所有的T-SQL程式碼後，再存取或修改資料。

從另一資料表中新增資料列

您可以從資料表插入資料列到另一個資料表中。這可以透過在INSERT陳述式中使用衍生資料表，或在傳回資料列的預存程序中使用EXECUTE子句來完成。

說明

衍生資料表（Derived Table）即為來自另一個T-SQL陳述式FROM子句中的SELECT陳述式結果集，在 第十四章 中會討論到衍生資料表。

現在來示範如何使用衍生資料表插入資料。首先建立資料表，命名為two_newest_items，並將item資料表中的兩筆資料列插入two_newest_items，以下是建立新資料表所使用的CREATE TABLE陳述式：

    CREATE TABLE two_newest_items
    (
    item_id    SMALLINT     NOT NULL,
    item_desc  VARCHAR(30)  DEFAULT 'no desc'
    )
    GO

要從items資料表將item_id和item_desc資料行中最新的值插入two_newest_items資料表，請使用下面的INSERT陳述式：

    INSERT INTO two_newest_items
        (item_id, item_desc)
    SELECT TOP 2 item_id, item_desc FROM items
    ORDER BY item_id DESC
    GO

請注意這裡使用的是SELECT陳述式，而不是列在INSERT陳述式的值清單。SELECT陳述式從一個已存在的資料表中傳回資料，傳回的資料當成值清單。另外，注意在SELECT陳述式上並沒有加括號，因為括號將造成傳回語法錯誤。

要查詢新資料表中所有資料列，可使用下列程式碼：

    SELECT * FROM two_newest_items

所顯示的結果集如下：

    item_id item_desc
    -------------------------
    3       No desc
    2       fried pork skins

請注意，我們在這裡的INSERT陳述式中使用ORDER BY子句，使item_id的資料列遞減排序。

如果我們將前面的SELECT陳述式建立為預存程序，使用EXECUTE陳述式加上預存程序名稱，也可以得到同樣的結果（預存程序將會在 第二十一章 介紹）。操作的方法為，首先使用DELETE陳述式刪除two_newest_items資料表中現存的所有資料列。（詳細細節請參閱本章稍後的 〈DELETE陳述式〉 。）然後建立一個預存程序，命名top_two，並用EXECUTE陳述式插入兩個新資料列到two_newest_items資料表。操作的T-SQL陳述式為：

    DELETE FROM two_newest_items
    GO
    CREATE PROCEDURE top_two
    AS
    SELECT TOP 2 item_id, item_desc FROM items
    ORDER BY item_id DESC
    GO
    INSERT INTO two_newest_items
        (item_id, item_desc)
    EXECUTE top_two
    GO

現在可以看到，我們已經使用top_two預存程序成功地插入兩個新的資料列。

相關資訊

INSERT陳述式可以用於指定資料表提示（Table Hints）。要詳細了解可以和INSERT陳述式一起使用的資料表提示，請使用《線上叢書》，在搜尋標籤頁中輸入 鎖定提示 ，選擇 鎖定提示 主題。

UPDATE陳述式

UPDATE陳述式用於修改或更新存在的資料，基本語法如下：

    UPDATEtable_nameSETcolumn_name = expression
        [FROMtable_source] WHERE search_condition

更新資料列

本範例將使用之前的items範例資料表，首先更新之前沒有輸入價格的junk food資料列。要識別資料列，將搜尋條件指定為fried pork skins，用下列陳述式更新價格至 $2元：

    UPDATE items SET price = 2.00
    WHERE item_desc = 'fried pork skins'
    GO

然後使用查詢選出junk food資料列：

    SELECT * FROM items
    WHERE item_desc = 'fried pork skins'
    GO

junk food資料列輸出顯示如下，原來的NULL值被2.00所替代：

    item_category   item_id price           item_desc
    --------------  ----------------------- ------------
    junk food       2       2.00    fried pork skins

您也可以使用以下的陳述式將價格增加10%：

    UPDATE items SET price = price * 1.10
    WHERE item_desc = 'fried pork skins'
    GO

現在如果選擇junk food資料列，價格已變更至 $2.20（$2乘以1.10的結果）；其他項目的價格則維持不變。

使用UPDATE陳述式可以更新一個以上的資料列。舉例來說，可以將所有資料列的價格都增加10%，其陳述式如下：

    UPDATE items SET price = price * 1.10
    GO

得到的輸出結果如下：

    item_category   item_id price   item_desc
    --------------- --------------- -----------------
    health food     1       4.40    tofu 6 oz.
    junk food       2       2.42    fried pork skins
    toys            3       NULL    No desc

價格設為NULL的資料列不會變動（因為NULL* 1.10還是等於NULL），這樣的執行方式是可以接受的，不會產生錯誤訊息。

使用FROM子句

UPDATE陳述式可利用FROM子句指定更新操作中的資料來源，資料來源清單可以包含資料表名稱、檢視表名稱、資料列及函數、衍生資料表和聯結資料表，甚至更新中的資料表也可以當成資料表來源。以下是範例，首先利用CREATE TABLE陳述式建立一個新的資料表，命名為tax，再用INSERT陳述式插入新的資料列，在tax_percent資料行中將值設為5.25。

    CREATE TABLE tax
    (
    tax_percent   real            NOT NULL,
    change_date   smalldatetime   DEFAULT getdate( )
    )
    GO
    INSERT INTO tax
        (tax_percent) VALUES (5.25)
    GO

由於沒有設定日期和時間，change_date資料行會使用預設值，由GETDATE函數得到目前的日期和時間。

現在在item資料表中新增一個新的資料行，命名為price_with_tax，並允許NULL值，陳述式如下：

    ALTER TABLE items
    ADD price_with_tax smallmoney NULL
    GO

接下來要更新所有price_with_tax資料行，這個資料行的資料是由items.price * tax.tax_percent運算而來。使用UPDATE陳述式和FROM子句如下：

    UPDATE items
    SET price_with_tax = i.price +
        (i.price * t.tax_percent / 100)
    FROM items i, tax t
    GO

在price資料行有數值的資料列，在price_with_tax資料行也會出現運算後的數值；如果原price資料行的資料為NULL，則相對應的price_with_tax也會出現NULL（NULL乘以任何值還是NULL），運算後的結果集如下（結果也包含所有先前對資料所做的修改）：

    item_category   item_id price   item_desc       price_with_tax
    --------------  ------- ------  --------------- ------------------
    health food     1       4.40    tofu 6 oz       4.63
    junk food       2       2.42    fried pork skin 2.55
    toys            3       NULL    No desc         NULL

如果在資料表中新增記錄，可以考慮執行之前的UPDATE陳述式，但這樣會再次更新price_with_tax資料行，浪費程序時間。要避免這種情況，可以使用UPDATE陳述式的WHERE子句，讓SQL Server更新price_with_tax中只含有NULL值的資料行。

    UPDATE items
    SET price_with_tax = i.price +
        (i.price * t.tax_percent / 100)
    FROM items i, tax t
    WHERE i.price_with_tax IS NULL
    GO

UPDATE陳述式非常適合當作觸發程序，當插入一個值到price資料行時，便會執行。觸發程序是一種特殊的預存程序，在某一特定的條件下會自動執行。觸發程序將在

第二十二章 中加以討論。

使用衍生資料表

使用UPDATE陳述式的另一個方法是在FROM子句中附帶一個衍生資料表或子查詢。然後衍生資料表就可以當成外部UPDATE的輸入。使用範例，我們將在子查詢中使用two_newest_items資料表，在外部UPDATE陳述式中使用items資料表。我們想要更新items資料表中的兩列資料，以使price_with_tax資料行儲存NULL值，可以利用查詢two_newest_items資料表，即可找出資料列中需要更新的item_id值：

    UPDATE items
    SET price_with_tax = NULL
    FROM (SELECT item_id FROM two_newest_items) AS t1
    WHERE items.item_id = t1.item_id
    GO

SELECT陳述式當成子查詢，其結果會放入命名為t1的暫存衍生資料表中，此資料表會被WHERE子句當成搜尋條件。子查詢的結果產生item_id的2和3兩個值，只要在item_id資料行中有2或3這兩個值，就會被影響。在item_id值為3的資料列，因為對應的price_with_tax資料行已有NULL值，故不會再改變；而在item_id值為2的資料列則更新為NULL值。結果集如下：

    item_category  item_id price   item_desc        price_with_tax
    -------------- ------- -----   ---------------  --------------
    health food    1       4.40    tofu 6 oz.       2.30
    junk food      2       2.42    fried pork skins NULL
    toys           3       NULL    No desc          NULL

DELETE陳述式

DELETE陳述式用於從資料表或檢視表中移除（刪除）一個或多個資料列。DELETE不影響資料表定義；只是從資料表中刪除資料列。DELETE陳述式的基本語法如下：

    DELETE [FROM]table_name|view_name
        [FROMtable_sources] WHEREsearch_condition

第一個和第二個FROM關鍵字可視需要使用。在第二個FROM子句中，資料表來源中的資料列不會被刪除，但會從DELETE後指定的table_name或view_name中被刪除。

刪除個別資料列

在DELETE中使用WHERE子句，可以指定從資料表中刪除特定的資料列。舉例來說，要從items資料表中刪除item_category中toy這個資料列，執行下面的敘述：

    DELETE FROM items
    WHERE item_category = 'toy'
    GO

該陳述式從items資料表中刪掉了一列。

使用一個或多個資料表來源的第二個FROM子句，可指定其他資料表或檢視表，供WHERE搜尋條件使用。例如，要從items資料表中刪除對應於two_newest_items資料表中的資料列，可執行下面的陳述式：

    DELETE items
    FROM two_newest_items
    WHERE items.item_id = two_newest_items.item_id
    GO

請注意，在這個陳述式中，two_newest_items資料表中的item_id資料列含有2和3的值，而items資料表中的item_id資料列則含有1和2的值，所以2就被刪除（因為符合搜尋條件）。在two_newest_items資料表（資料來源）的兩個資料列則不受影響。

刪除所有資料列

要刪除資料表中的所有資料列，可利用DELETE陳述式。下面的DELETE陳述式將刪除two_newest_items資料表中的所有資料列：

    DELETE FROM two_newest_items
    GO

現在two_newest_items資料表是一個空的資料表，即不包含資料列的資料表。如果想刪除資料表定義，請使用

第十五章 說明的DROP TABLE指令：

    DROP TABLE two_newest_items
    GO

相關資訊

在《線上叢書》中可找到更多使用DELETE的方法，例如利用聯結資料表作為資料表來源，以及使用資料表和查詢提示，請在《線上叢書》索引中查閱DELETE並選擇相關的次主題。

程式設計關鍵字

T-SQL陳述式中有幾個有用的程式設計結構關鍵字，能用來控制程式流程。這些結構可用於批次處理（一次執行一組T-SQL陳述式）、預存程序、指令碼和特別的查詢（本節範例會使用pubs資料庫）。

IF...ELSE

IF...ELSE結構利用條件以決定將執行那一條T-SQL陳述式，語法如下：

    IFBoolean_expression
    T-SQL_statement | block_of_statements
    [ELSET-SQL_statement | block_of_statements]

布林運算式（Boolean Expression）指的是傳回TRUE或FALSE的運算式。如果IF子句中的運算式傳回TRUE，陳述式將執行，ELSE子句及其敘述則不執行；如果運算式傳回FALSE，就會只執行ELSE關鍵字後的敘述。 陳述式區塊（block_of_statements） 代表一個以上的T-SQL陳述式。使用陳述式區塊時，無論該陳述式區塊在IF子句中、ELSE子句中或是兩者都有，都必須用關鍵字BEGIN和END來指定區塊的開始和結束。

您也可以使用沒有ELSE子句的IF子句。現在我們先來看看只使用IF子句的範例，下面的程式碼將檢查運算式，如果運算式傳回TRUE，將執行接下來的PRINT陳述式：

    IF (SELECT ytd_sales FROM titles
        WHERE title_id = 'PC1035') > 5000
    PRINT 'year-to-date sales are
        greater than $5,000 for PC1035.'
    GO

因為title_id = 'PC1035'資料列ytd_sales的值是8780（大於5000），因此IF運算式將計算為TRUE，並執行PRINT陳述式，將「Year-to-date sales are greater than $5,000 for PC1035」列印在螢幕上。

現在將一個ELSE子句新增到上面的範例中，並將> 5000變為> 9000。IF...ELSE顯示如下：

    IF (SELECT ytd_sales FROM titles
        WHERE title_id = 'PC1035') > 9000
    PRINT 'yeartodate sales are
        greater than $9,000 for PC1035.'
    ELSE
    PRINT 'yeartodate sales are
        less than $9,000 for PC1035.'
    GO

在本範例中，由於IF運算式傳回FALSE。ELSE子句後的列印陳述式將被執行。

讓我們更進一步擴展以上的範例，並在IF和ELSE子句中新增陳述式區塊。根據IF條件傳回的結果，列印訊息後執行查詢，下面是範例程式碼：

    IF (SELECT ytd_sales FROM titles WHERE title_id = 'PC1035') > 9000
    BEGIN
        PRINT 'year-to-date sales are
            greater than $9,000 for PC1035.'
        SELECT ytd_sales FROM titles
            WHERE title_id = 'PC1035'
    END
    ELSE    -- ytd_sales必須小與或等於9000.
    BEGIN
            PRINT 'year-to-date sales are
                less than or equal to $9,000 for PC1035.'
            SELECT price FROM titles
                WHERE title_id = 'PC1035'
    END
    GO

IF計算式結果是FALSE，所以會執行ELSE子句中BEGIN和END之間的敘述：執行PRINT後接著執行SELECT陳述式，顯示書價為 $22.95。

您也可以在IF子句或ELSE子句後使用巢狀的IF陳述式。舉例來說，可執行下面的程式碼，使用巢狀的IF...ELSE陳述式找出ytd_sales平均值的範圍：

    IF (SELECT avg(ytd_sales) FROM titles) < 10000
        IF (SELECT avg(ytd_sales) FROM titles) < 5000
            IF (SELECT avg(ytd_sales) FROM titles) < 2000
                PRINT 'Average year-to-date sales are
                less than $2,000.'
            ELSE
            PRINT 'Average year-to-date_ sales are
                between $2,000 and $4,999.'
            ELSE
            PRINT 'Average year-to-date sales are
                between $5,000 and $9,999.'
    ELSE
    PRINT 'Average year-to-date sales are greater
            than $9,999.'
    GO

當您執行該程式碼時，將會看到兩次這樣的訊息：「警告：彙總（aggregate）或其他SET操作已消除Null值。」該訊息表示資料表計算平均數時，在ytd_sales資料行的NULL值未被使用，也未被當成值來計算。由於平均值是 $6,090，該程式碼所得到最後結果是「Average year-to-date sales are between $5,000 and $9,999.」。請注意，當使用IF陳述式時，很容易就把IF應該和哪個ELSE為一組混淆，或者有了IF但忘了指示ELSE，所以用TAB鍵（如上所示）是不錯的辦法。

WHILE

該條件判斷式是設定SQL陳述式或陳述式區塊重複執行的條件。只要指定條件為TRUE，陳述式會一直重複執行。這就是所謂的WHILE迴圈（Loop），因為WHILE結構中的程式碼在迴圈中重複。語法顯示如下：

    WHILEBoolean_expression
    SQL_statement | block_of_statements
    [BREAK]SQL_statement | block_of_statements
    [CONTINUE]

同上述的IF...ELSE，使用BEGIN和END來指定WHILE迴圈中陳述式的起始和結束。BREAK關鍵字則將導致從WHILE迴圈中跳出，然後接著執行WHILE迴圈結束後的陳述式。如果一個WHILE迴圈與另一個WHILE迴圈是巢狀結構，BREAK關鍵字只會從被包含的WHILE迴圈中跳出，繼續執行該迴圈外所有的的陳述式和迴圈。CONTINUE關鍵字指定WHILE迴圈重新執行BEGIN和END之間的陳述式，忽略CONTINUE之後的其他陳述式。

現在使用簡單的WHILE迴圈重複執行UPDATE陳述式。WHILE迴圈的檢測條件為：royalty資料行的平均值是否少於20。如果檢測傳回TRUE，所有royalty資料列的值都會增加5%。接著再次檢測WHILE條件，重複更新直到royalty欄位的平均值為20或更多。程式碼如下：

    WHILE (SELECT AVG(royalty) FROM roysched) < 20
    UPDATE roysched SET royalty = royalty * 1.05
    GO

由於royalty資料行原來的平均值是15，因此在平均值達到20前，WHILE迴圈共執行了21次，直到檢測條件回傳值為FALSE時才停止。

現在看一個在WHILE迴圈中使用BREAK、CONTINUE、BEGIN和END的範例。我們將執行迴圈直到royalty的平均值達到25。但如果在迴圈中，royalty的最大值超過27，將中斷迴圈，並在WHILE迴圈結束後加一個SELECT陳述式。下面是T-SQL程式碼：

    WHILE (SELECT AVG(royalty) FROM roysched) < 25
    BEGIN
    UPDATE roysched SET royalty = royalty * 1.05
    IF (SELECT MAX(royalty) FROM roysched) > 27
    BREAK
    ELSE
    CONTINUE
    END
    SELECT MAX(royalty) AS "MAX royalty" FROM roysched
    GO

資料表中已經存在的royalty值大於27，因此只執行一次迴圈，而royalty的平均值小於25%，因此UPDATE執行一次；接著IF陳述式檢測並傳回TRUE，所以執行BREAK，跳出WHILE迴圈；最後執行END關鍵字後的陳述式，也就是SELECT陳述式。

您還能使用巢狀的WHILE迴圈，但記得BREAK或CONTINUE關鍵字只應用於呼叫它們的迴圈，而不是外部的WHILE迴圈。

CASE

CASE關鍵字用來評估各種條件的清單，並且傳回多種可能的結果運算式其中之一，最常見的用法是用來取代程式碼，或是使用具可讀性的數值（縮寫值），或者用來分類值，本節的範例將加以介紹。CASE被分為兩種格式：簡單（simple）格式和搜尋（searched）格式。簡單格式會使用CASE之後的運算式，與一組在WHEN之後的運算式做比較，以決定其結果；搜尋格式則評估一組布林運算式為TRUE或FALSE，以決定其結果。以下為簡單格式的語法：

    CASE input_expression
        WHEN when_expression THEN result_expression
        [WHEN when_expression THEN result_expression...n]
        [ELSE else_result_expression]
    END

when_expression和input_expression會依其在CASE子句中的排列順序進行比較，如果相對應的when_expression等於input_expression，將傳回result_expression值。如果沒有對應的值，將傳回指定的else_result_expression的值。如果沒有指定else_result_expression，則傳回NULL。注意在簡單格式CASE子句中，input_expression值和when_expression值的資料型別必須相同，或是資料型別之間允許隱含轉換。

下面的範例在SELECT陳述式中使用簡單格式的CASE子句。Sales資料表的payterms資料行包含了Net 30、Net 60、On invoice或None。這個T-SQL陳述式允許使用替代值（易於了解）以顯示payterms資料行：

    SELECT 'Payment Terms' =
    CASE payterms
        WHEN 'Net 30' THEN 'Payable 30 days
            after invoice'
        WHEN 'Net 60' THEN 'Payable 60 days
            after invoice'
        WHEN 'On invoice' THEN 'Payable upon
            receipt of invoice'
        ELSE 'None'
        END,
    title_id
    FROM sales
    ORDER BY payterms
    GO

CASE子句會檢測payterms資料行中，被SELECT陳述式中所指定每個資料列的值。當when_expression值等於payterms值，傳回result_expression的值。來自CASE子句的結果顯示在結果集中的Payment Terms資料行中，如下所示：

    Payment Terms                   title_id
    ------------------------------- -----------
    Payable 30 days after invoice   PC8888
    Payable 30 days after invoice   TC3218
    Payable 30 days after invoice   TC4203
    Payable 30 days after invoice   TC7777
    Payable 30 days after invoice   PS2091
    Payable 30 days after invoice   MC3021
    Payable 30 days after invoice   BU1111
    Payable 30 days after invoice   PC1035
    Payable 60 days after invoice   BU1032
    Payable 60 days after invoice   PS2091
    Payable 60 days after invoice   PS2091
    Payable 60 days after invoice   PS1372
    Payable 60 days after invoice   PS2106
    Payable 60 days after invoice   PS3333
    Payable 60 days after invoice   PS7777
    Payable 60 days after invoice   BU7832
    Payable 60 days after invoice   MC2222
    Payable upon receipt of invoice PS2091
    Payable upon receipt of invoice BU2075
    Payable upon receipt of invoice MC3021
    Payable upon receipt of invoice BU1032

    (影響21個資料列)

現在我們來看看搜尋格式的CASE子句，語法如下：

    CASE
       WHENBoolean_expressionTHENresult_expression
       [WHENBoolean_expressionTHENresult_expression...n]
       [ELSEelse_result_expression]
    END

簡單格式與搜尋格式的CASE子句其區別在於：搜尋格式的CASE子句在CASE關鍵字後沒有input_expression值，而在WHEN關鍵字後以Boolean運算式檢測TRUE或FALSE，並不像簡單格式比較運算式之間是否相等。搜尋格式的CASE子句依照各個運算式排列的順序檢測Boolean_expression值，並傳回評估為TRUE的第一個result_expression值。

舉例來說，下面的SELECT陳述式中的CASE子句將檢測每一個資料列的price值，並且以書的價格範圍為標準，比較資料列中的price值，傳回一個字串：

    SELECT 'Price Range' =
        CASE
           WHEN price BETWEEN .01 AND 10.00
               THEN 'Inexpensive: $10.00 or less'
           WHEN price BETWEEN 10.01 AND 20.00
               THEN 'Moderate: $10.01 to $20.00'
           WHEN price BETWEEN 20.01 AND 30.00
               THEN 'Semi-expensive: $20.01 to $30.00'
           WHEN price BETWEEN 30.01 AND 50.00
               THEN 'Expensive: $30.01 to $50.00'
           WHEN price IS NULL
               THEN 'No price listed'
           ELSE 'Very expensive!'
        END,
    title_id
    FROM titles
    ORDER BY price
    GO

結果集顯示如下：

    Price Range                     title_id
    ------------------------------- ----------
    No price listed                 MC3026
    No price listed                 PC9999
    Inexpensive: $10 or less        MC3021
    Inexpensive: $10 or less        BU2075
    Inexpensive: $10 or less        PS2106
    Inexpensive: $10 or less        PS7777
    Moderate: $10.01 to $20         PS2091
    Moderate: $10.01 to $20         BU1111
    Moderate: $10.01 to $20         TC4203
    Moderate: $10.01 to $20         TC7777
    Moderate: $10.01 to $20         BU1032
    Moderate: $10.01 to $20         BU7832
    Moderate: $10.01 to $20         MC2222
    Moderate: $10.01 to $20         PS3333
    Moderate: $10.01 to $20         PC8888
    Semiexpensive: $20.01 to $30    TC3218
    Semiexpensive: $20.01 to $30    PS1372
    Semiexpensive: $20.01 to $30    PC1035

    (影響18個資料列)

說明

以上兩個CASE子句範例中，由於整個CASE子句是SELECT子句中 資料行清單 的一部份，所以我們在END關鍵字後插入了逗號後，才加入title_id資料行。換句話說，整個CASE子句在資料行清單中只是一個項目。這是CASE關鍵字最常被使用的方法。

其他關鍵字

以下為其他可用於控制程式流程的T-SQL關鍵字：

- GOTO label：當GOTO中定義了某label時，導向處理程序直接由該label後開始繼續處理。
- RETURN ：無條件從查詢或程序中退出。
- WAITFOR ：為陳述式的執行設定延遲或指定時間。

相關資訊

要詳細了解如何使用這些關鍵字，可在《線上叢書》索引中查閱GOTO、RETURN和WAITFOR，檢視對話方塊中所列的主題。

本章總結

在本章中，您學到了使用INSERT、UPDATE和DELETE的T-SQL陳述式，以及用來控制程式流程的關鍵字IF、ELSE、WHILE、BEGIN、END和CASE。

第二十一章 將學習如何建立預存程序，配合使用這些陳述式和結構。