查看 SELECT 陳述式
Transact-SQL (或 T-SQL) 是 Microsoft SQL 產品和服務所使用 ANSI 標準 SQL 語言的一種方言。 其類似於標準 SQL。 我們大部分的重點會放在 SELECT 陳述式上,其目前為止擁有任何 DML 陳述式的最多選項和變化。
首先讓我們概括看看如何處理 SELECT 陳述式。 撰寫 SELECT 陳述式的順序並不是 SQL Server 資料庫引擎評估和處理的順序。
請考慮以下查詢:
SELECT OrderDate, COUNT(OrderID) AS Orders
FROM Sales.SalesOrder
WHERE Status = 'Shipped'
GROUP BY OrderDate
HAVING COUNT(OrderID) > 1
ORDER BY OrderDate DESC;
此查詢包含一個由多個子句所組成的 SELECT 陳述式,其中每個子句都會定義必須套用至所擷取資料的特定作業。 雖然我們不會在本課程模組中討論不同子句的詳細資料,但在查看作業的執行階段順序之前,讓我們先簡短看看此查詢的功用。
SELECT 子句會傳回 OrderDate 資料行,以及 OrderID 值的計數,並為此計數指派 Orders 名稱 (或別名):
SELECT OrderDate, COUNT(OrderID) AS Orders
FROM 子句會識別哪個資料表是查詢的資料列來源;在此案例中為 Sales.SalesOrder 資料表:
FROM Sales.SalesOrder
WHERE 子句會從結果中篩選資料列,只保留滿足指定條件的資料列;在此案例中為具有「已出貨」(Shipped) 狀態的訂單:
WHERE Status = 'Shipped'
GROUP BY 子句接受符合篩選準則的資料列,並依 OrderDate 將其分組,如此一來,所有具有相同 OrderDate 的資料列都會被視為同一個群組,而且每個群組都會傳回一個資料列:
GROUP BY OrderDate
組成群組之後,HAVING 子句會根據本身的述詞篩選群組。 結果中只會包含具有多個訂單的日期:
HAVING COUNT(OrderID) > 1
基於預覽此查詢的目的,最後一個子句是 ORDER BY,t其會依 OrderDate 的遞減順序排序輸出:
ORDER BY OrderDate DESC;
現在您已瞭解每個子句的功用,讓我們看看 SQL Server 實際評估這些子句的順序:
- 首先評估 FROM 子句,以提供其餘陳述式的來源資料列。 虛擬資料表會隨即建立,並傳遞至下一個步驟。
- 下一個要評估的是 WHERE 子句,這會從來源資料表中篩選符合述詞的資料列。 篩選後的虛擬資料表會傳遞至下一個步驟。
- 下一個是 GROUP BY,這會根據在 [GROUP BY] 清單中所找到唯一值來組織虛擬資料表中的資料列。 新的虛擬資料表會隨即建立 (其中包含群組清單),並傳遞至下一個步驟。 從作業流程中的這個時間點開始,其他元素只能參考 [GROUP BY] 清單中的資料行或彙總函式。
- 下一個要評估的是 HAVING 子句,這會根據其述詞篩選出整個群組。 在步驟 3 中建立的虛擬資料表會經過篩選,並傳遞至下一個步驟。
- 然後執行 SELECT 子句,以判斷哪些資料行會出現在查詢結果中。 由於 SELECT 子句是在其他步驟之後評估,因此無法在 GROUP BY 或 HAVING 子句中使用此處所建立的任何資料行別名 (在我們的範例中為 Orders)。
- 最後一個要執行的是 ORDER BY 子句,這會依其資料行清單所決定的順序排序資料列。
為了將此理解應用到範例查詢,以下是上述 SELECT 陳述式的執行階段邏輯順序:
FROM Sales.SalesOrder
WHERE Status = 'Shipped'
GROUP BY OrderDate
HAVING COUNT(OrderID) > 1
SELECT OrderDate, COUNT(OrderID) AS Orders
ORDER BY OrderDate DESC;
您所撰寫每個 SELECT 陳述式不一定需要所有可能的子句。 唯一必要的子句是 SELECT 子句,在某些情況下可以單獨使用。 通常也會包含 FROM 子句,以識別要查詢的資料表。 此外,Transact-SQL 還有其他可新增的子句。
如您所見,您不會依邏輯評估時的相同順序撰寫 T-SQL 查詢。 評估的執行階段順序會決定哪些子句可使用哪些資料,因為子句只能存取經處理子句中已可使用的資訊。 基於這個理由,在撰寫查詢時,請務必瞭解真正的邏輯處理順序。
選取所有資料行
SELECT 子句通常稱為 SELECT「清單」,因為其會列出要在查詢結果中傳回的值。
SELECT 子句的最簡單格式是使用星號字元 (*) 傳回所有資料行。 在 T-SQL 查詢中使用時,這會稱為星型。 雖然 SELECT * 很適合進行快速測試,但您應該避免在生產工作中使用,原因如下:
- 新增或重新排列資料行的資料表變更將會反映在查詢結果中,而可能導致使用查詢的應用程式或報表出現非預期輸出。
- 傳回不需要的資料可能會讓查詢變慢,並在來源資料表包含大量資料列時造成效能問題。
例如,下列範例會從假設的 Production.Product 資料表擷取所有資料行。
SELECT * FROM Production.Product;
此查詢的結果是一個資料列集,其中包含資料表中所有資料列的所有資料行,如下所示:
ProductID
名稱
ProductNum
Color
StandardCost
ListPrice
大小
Weight
ProductCatID
680
HL 公路車架 - 黑色,58
FR-R92B-58
黑色
1059.31
1431.5
58
1016.04
18
706
HL 公路車架 - 紅色,58
FR-R92R-58
紅
1059.31
1431.5
58
1016.04
18
707
Sport-100 安全帽,紅色
HL-U509-R
紅
13.0863
34.99
35
708
Sport-100 安全帽,黑色
HL-U509
黑色
13.0863
34.99
35
...
...
...
...
...
...
...
...
...
選取特定資料行
明確的資料行清單可讓您控制實際所要傳回資料行和其順序。 結果中的每個資料行都會以資料行名稱作為標頭。
例如,請考慮下列查詢,這會再次使用假設的 Production.Product 資料表。
SELECT ProductID, Name, ListPrice, StandardCost
FROM Production.Product;
這次,結果只會包含指定的資料行:
ProductID
名稱
ListPrice
StandardCost
680
HL 公路車架 - 黑色,58
1431.5
1059.31
706
HL 公路車架 - 紅色,58
1431.5
1059.31
707
Sport-100 安全帽,紅色
34.99
13.0863
708
Sport-100 安全帽,黑色
34.99
13.0863
...
...
...
...
選取運算式
除了擷取儲存在指定資料表中的資料行之外,SELECT 子句還可以執行計算和操作,其使用運算子合併資料行和值或多個資料行。 此計算或操作的結果必須是單一值 (純量) 結果,這會以個別資料行的形式出現在結果中。
例如,下列查詢包含兩個運算式:
SELECT ProductID,
Name + '(' + ProductNumber + ')',
ListPrice - StandardCost
FROM Production.Product;
此查詢的結果如下所示:
ProductID
680
HL Road Frame - Black, 58(FR-R92B-58)
372.19
706
HL Road Frame - Red, 58(FR-R92R-58)
372.19
707
Sport-100 Helmet, Red(HL-U509-R)
21.9037
708
Sport-100 Helmet, Black(HL-U509)
21.9037
...
...
...
這些結果有兩點需要注意的事項:
- 這兩個運算式所傳回的資料行沒有資料行名稱。 視您用於提交查詢的工具而定,遺漏的資料行名稱可能會以空白資料行標頭、常值「沒有資料行名稱」指標或預設名稱 (例如 column1) 表示。 我們將在本節稍後的查詢中了解如何指定資料行名稱的「別名」。
- 第一個運算式使用 + 運算子串連字串值 (以字元為主),而第二個運算式則使用 - 運算子從另一個數值減去一個數值。 搭配數值使用時,+ 運算子會執行加法。 很明顯地,您必須瞭解包含在運算式中資料行的「資料類型」。 我們將在下一節討論資料類型。
指定資料行別名
您可以指定 SELECT 查詢所傳回每個資料行的「別名」,其用於替代來源資料行名稱,或指派名稱給運算式的輸出。
例如,以下是與之前相同的查詢,但具有針對每個資料行指定的別名:
SELECT ProductID AS ID,
Name + '(' + ProductNumber + ')' AS ProductName,
ListPrice - StandardCost AS Markup
FROM Production.Product;
此查詢結果會包含指定的資料行名稱:
識別碼
ProductName
標記
680
HL Road Frame - Black, 58(FR-R92B-58)
372.19
706
HL Road Frame - Red, 58(FR-R92R-58)
372.19
707
Sport-100 Helmet, Red(HL-U509-R)
21.9037
708
Sport-100 Helmet, Black(HL-U509)
21.9037
...
...
...
注意
指定別名時,AS 關鍵字為選擇性,但為了釐清起見,建議將其納入。
將查詢格式化
您可能會在本節的範例中注意到,您可以彈性地決定要如何將查詢程式碼格式化。 例如,您可以將每個子句 (或整個查詢)撰寫成一行,或將其分成多行。 在大多數資料庫系統中,程式碼不區分大小寫,而且 T-SQL 語言的某些元素為選擇性 (包括先前提到的 AS 關鍵字,甚至是陳述式結尾的分號)。
請考慮下列方針,以讓 T-SQL 程式碼更容易閱讀 (因此更容易瞭解和偵錯):
- 將 T-SQL 關鍵字變成大寫,例如 SELECT、FROM、AS 等。 將關鍵字變成大寫是常用的慣例,可讓您更輕鬆地尋找複雜陳述式的每個子句。
- 針對陳述式的每個主要子句另起新行。
- 如果 SELECT 清單不是只包含幾個資料行、運算式或別名,請考慮將每個資料行分行列出。
- 將包含次子句或資料行的行縮排,以清楚指出每個主要子句所屬的程式碼。