不管哪一種語言都具備流程控制的功能,用來控制程式執行與流程的流向,透過流程控制可以讓程式更容易維護。
這次要討論根據特定條件來執行不同流程的指令:IF...ELSE。
很多人都以為 IF 後面一定要跟著 ELSE 子句,其實是可以不用的。例如,在建立資料表之前,通常都會檢查是否已經存在相同名稱的資料表:
-- 檢查資料表是否已經存在,如果存在,就把它刪除掉
IF OBJECT_ID(N'myTable', N'U') IS NOT NULL
DROP TABLE myTable
通常我們會使用代碼來儲存資料,例如在性別欄位中,使用 M 代表男性,使用 F 代表女性。而在顯示這類欄位的資料時,就可以使用 IF...ELSE 來將代碼轉換成文字描述,這樣才能讓然人家清楚的知道資料所代表的意義是什麼:
USE AdventureWorks
GO
-- 定義變數
DECLARE @EmployeeID int, @Gender nchar(1), @ChineseGender nchar(2)
-- 定義 CURSOR
DECLARE myCursor CURSOR FOR
SELECT EmployeeID, Gender FROM HumanResources.Employee
-- 開啟 CURSOR
OPEN myCursor
-- 抓出資料
FETCH NEXT FROM myCursor
INTO @EmployeeID, @Gender
-- 檢查 @@FETCH_STATUS 來決定是否要繼續執行
WHILE (@@FETCH_STATUS = 0)
BEGIN
PRINT N'員工編號:' + CAST(@EmployeeID AS NCHAR(10))
IF @Gender = 'M'
SET @ChineseGender = N'男'
ELSE
SET @ChineseGender = N'女'
PRINT N'性別:' + @ChineseGender
PRINT REPLICATE('-', 20)
FETCH NEXT FROM myCursor
INTO @EmployeeID, @Gender
END
-- 關閉 CURSOR
CLOSE myCursor
-- 釋放 CURSOR
DEALLOCATE myCursor
執行的部分結果如下:
最後我們討論使用 IF...ELSE 跟資料庫效能的一個重要議題。
假設資料表中,當某個欄位的欄位值已經存在資料,就要更新這些資料,如果沒有相關的資料存在,就要新增一筆資料。通常我們會直覺的使用下面這種寫法:
-- 計算筆數
IF (SELECT COUNT(*) FROM myTable WHERE 欄位名稱='欄位值') > 0
UPDATE myTable SET (...) WHERE 欄位名稱='欄位值'
ELSE
INSERT INTO myTable VALUES (...)
因為我們只是要檢查是否存在任何相符的記錄,根本不需要知道有多少筆資料,所以應該改用 IF EXISTS 來取代 SELECT COUNT(*)。這麼一來,只要找到第一筆相符的資料時,IF EXISTS 就會馬上停止搜尋,也就是說,根本不需要再多花費其他額外的時間,就已經知道至少存在一筆相符的資料了。所以應該要將程式碼改寫成下面這樣:
-- 檢查資料是否已經存在
IF EXISTS (SELECT * FROM myTable WHERE 欄位名稱='欄位值')
UPDATE myTable SET (...) WHERE 欄位名稱='欄位值'
ELSE
INSERT INTO myTable VALUES (...)
但是上面那種寫法並不是最好的方法,因為在執行 SELECT 或 UPDATE 指令時,都會進行 Table Scan 或 Index Scan,也就是說最多會進行 2 次 SCAN,最少 1 次 SCAN。在改用下面的寫法之後,可以確保最多只會執行 1 次 Table Scan 或 Index Scan:
-- 更新資料表
UPDATE myTable SET (...) WHERE 欄位名稱='欄位值'
-- 檢查更新的資料筆數是否為 0,是 0 的話,就表示根本沒相符的資料要更新
-- 所以要新增一筆新的資料
IF @@ROWCOUNT = 0
INSERT INTO myTable VALUES (...)