查看 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 實際評估這些子句的順序:

  1. 首先評估 FROM 子句,以提供其餘陳述式的來源資料列。 虛擬資料表會隨即建立,並傳遞至下一個步驟。
  2. 下一個要評估的是 WHERE 子句,這會從來源資料表中篩選符合述詞的資料列。 篩選後的虛擬資料表會傳遞至下一個步驟。
  3. 下一個是 GROUP BY,這會根據在 [GROUP BY] 清單中所找到唯一值來組織虛擬資料表中的資料列。 新的虛擬資料表會隨即建立 (其中包含群組清單),並傳遞至下一個步驟。 從作業流程中的這個時間點開始,其他元素只能參考 [GROUP BY] 清單中的資料行或彙總函式。
  4. 下一個要評估的是 HAVING 子句,這會根據其述詞篩選出整個群組。 在步驟 3 中建立的虛擬資料表會經過篩選,並傳遞至下一個步驟。
  5. 然後執行 SELECT 子句,以判斷哪些資料行會出現在查詢結果中。 由於 SELECT 子句是在其他步驟之後評估,因此無法在 GROUP BY 或 HAVING 子句中使用此處所建立的任何資料行別名 (在我們的範例中為 Orders)。
  6. 最後一個要執行的是 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 清單不是只包含幾個資料行、運算式或別名,請考慮將每個資料行分行列出。
  • 將包含次子句或資料行的行縮排,以清楚指出每個主要子句所屬的程式碼。