[翻譯]通往t - sql的階梯:超越基本級別2:編寫子查詢

通往t - sql的階梯:超越基本級別2:編寫子查詢sql

格雷戈裏·拉森(Gregory Larsen)2016/01/01(第一次出版:2014 /01/ 29)數據庫

 

該系列函數

  這篇文章是樓梯系列的一部分:通往t - sql的樓梯:超越基礎。工具

  從他的階梯到t - sql DMLGregory Larsen涵蓋了t - sql語言的更高級的方面,如子查詢。sqlserver

  在開始建立比基本transact - SQL語句更復雜的SQL代碼時,您可能會發現須要使用其餘SELECT語句的結果來約束您的查詢。當您在父transact - sql語句中嵌入SELECT語句時,這些嵌入的SELECT語句被稱爲子查詢或相關子查詢。在這個層次的基礎上,我將討論子查詢的不一樣方面,在之後的級別中,我將討論相關的子查詢。性能

 

子查詢是什麼?測試

  子查詢只是在另外一個transact - sql語句中包含的SELECT語句。能夠在任何可使用表達式的地方使用子查詢。許多子查詢返回單個列值,由於它們與比較運算符一塊兒使用(=!=< =>> =)或表達式。當子查詢不用做表達式或與比較運算符使用時,它能夠返回多個值。此外,子查詢甚至能夠返回多個列和值,當它們在FROM子句或關鍵字中使用時。優化

  在transact - sql語句中很容易發現子查詢,由於它將是括號中包含的SELECT語句。因爲子查詢包含在transact - sql語句中,子查詢一般被稱爲內部查詢。而包含子查詢的transact - sql語句被稱爲外部查詢。子查詢的另外一個特性是,它能夠獨立於外部查詢運行,而且將運行沒有錯誤,而且可能返回一組行,或者返回一個空行集。spa

  子查詢的另外一種形式是相關子查詢。可是關聯子查詢不能獨立於外部Transact SQL語句運行。關聯子查詢使用來自外部查詢的列或列來約束從相關子查詢返回的結果。對於本文的相關子查詢,這已經足夠了。我將在將來的樓梯文章中探索相關的子查詢。3d

  如下是使用子查詢時須要考慮的其餘事項:

ntext、文本和圖像數據類型不容許從子查詢返回

•除非使用頂部運算符,不然不能在子查詢中使用ORDER BY子句

•使用子查詢的視圖不能更新

•在子查詢中不能使用computeINTO子句

 

子查詢示例的示例數據

  爲了演示如何使用子查詢,我須要一些測試數據。個人全部示例都將使用AdventureWorks2008R2數據庫,而不是建立本身的測試數據。若是您想要跟隨並運行我在您的環境中的示例,那麼您能夠從這裏下載AdventureWorks2008R2數據庫:

http://msftdbprodsamples.codeplex.com/releases/view/93587

 

返回單個值的子查詢示例

  如上所述,在比較操做符的一側使用表達式或返回值的子查詢須要返回一個值。transact - sql語句中有許多不一樣的地方須要子查詢返回一個列值,就像在一個選擇列表,where子句,等等。在本節中,我將提供一系列的例子將演示使用子查詢表達式或比較運算符,以知足不一樣的業務需求。

 

子查詢列列表中

  列表中的子查詢是一個SELECT語句,它返回SELECT子句的列列表中的單個列值。爲了演示如何在選擇列表中使用子查詢,咱們假設必須從SELECT語句中生成一個具備如下業務需求的結果集:

•歸還全部的銷售。SalesOrderHeader記錄了一個訂單日期等於「2007 -02-19 00:00. 00

•按SalesOrderID順序訂購返回的記錄

•每一行返回最古老的順序的行數爲1的行數,下一個最大的行數爲2,等等

•結果集須要一個名爲TotalOrders的列,該列須要填滿整個訂單的數量,該訂單的訂單數量等於「2007 -02-19 00:00. 00

知足這些需求的代碼如清單1所示。

 

清單1:列列表中的子查詢

  在這個transact - sql語句中,您能夠看到兩個不一樣的SELECT子句。子查詢是在清單1的語句中嵌入的SELECT語句,它周圍有括號。我已經提取了子查詢語句並將其放入清單2中,以防您想要測試驗證它是否能夠獨立於完整的transact - sql語句運行。

 

清單2:在清單1中找到的子查詢語句

  經過在列列表中擁有這個子查詢,Listing1中的transact - sql語句可以計算有一個OrderDate2007 -02-19 00:00. 000」的SalesOrderHeader行的數量,並返回該信息以及關於銷售的詳細行信息。有相同的OrderDate值的SalesOrderHeader記錄。

 

子查詢在WHERE子句中的例子

  有時您但願根據SELECT語句的結果來驅動WHERE子句條件。當您在WHERE子句中選擇語句時,這個SELECT語句其實是一個子查詢。爲了演示在WHERE子句中使用子查詢,假設您須要顯示銷售。SalesOrderDetail記錄包含購買超大的長袖標誌運動衫。清單3中的代碼使用子查詢知足個人顯示需求。

 

 

清單3:WHERE子句中的子查詢

  清單3中的子查詢位於WHERE條件的右側。這個子查詢標識生產的產品。產品名稱的產品名稱爲「長袖標誌球衣,XL」。這個子查詢容許我找到全部的銷售。SalesOrderDetail記錄有一個與「長袖Logo Jersey,XL」的產品名稱相關的產品。

 

示例使用子查詢來控制TOP子句

  使用TOP子句返回的行數能夠由表達式控制。清單5中的代碼標識了銷售數量。SalesOrderDetail行應該基於頂部子句中的子查詢返回。

 

清單4:TOP子句中的子查詢

  清單4中的代碼使用從子查詢返回的OrderQty值來標識將在TOP子句中使用的值。經過使用子查詢來控制TOP子句返回的行數,能夠建立一個子查詢,該子查詢將動態識別在運行時從查詢返回的行數。

 

子查詢在HAVING子句中的例子

  爲了演示在「有」子句中使用子查詢,假設您有如下業務需求:

生成包含sales . salesorderheader的結果集。訂單日期和每一個日期的訂單數量,其中訂單數量超過了「2006 -05- 01」的訂單數量。

爲了知足這一要求,我已經開發了清單6中的查詢,其中使用了「HAVING子句」中的子查詢。

 

 

清單5:HAVING子句中的子查詢

  清單5中的代碼在有子句的右邊有子查詢,並在個人子查詢中使用COUNT函數來肯定在「2006-05-01」上放置的訂單數量。

 

在函數調用中使用子查詢的例子

  爲了演示在函數調用中使用子查詢,假設您有要求在OrderDate和每一個Sales的最大OrderDate之間顯示天數。SalesOrderHeader記錄。清單6中的代碼知足這一需求。

 

清單6:函數調用中的子查詢

  清單6中的代碼有兩個不一樣的子查詢。兩個子查詢都返回Sales中的max OrderDateSalesOrderHeader表。可是,第一個子查詢用於將日期傳遞給DATEDIFF函數的第二個參數。

 

返回多個值的子查詢示例

  到目前爲止,個人全部示例都包含子查詢,這些子查詢僅在單個列中返回單個值。並非全部的子查詢都有這樣的要求。接下來的幾個示例將使用返回多個值和/或多個列的子查詢。

 

子查詢在FROM子句中的示例

  在FROM子句中,您一般肯定您的transact - sql語句將針對的表或表集合。每一個表提供一組記錄,您的查詢將使用這些記錄來肯定您的查詢的最終結果集。子查詢能夠看做是返回一組記錄的查詢,所以它能夠像表同樣在FROM子句中使用。清單7中的查詢顯示了我如何在FROM子句中使用子查詢。在FROM子句中使用子查詢時,子查詢生成的結果集一般稱爲派生表。

 

 

清單7:FROM子句中的子查詢

  清單7中的代碼使用FROM子句中的子查詢建立一個表別名,名爲Last10SalesOrders。個人子查詢返回了最後10個銷售。alesOrderDetail記錄包含一個716的產品。

  在清單7中,個人代碼是一個很是簡單的例子,說明如何在FROM子句中使用子查詢。經過使用FROM子句中的子查詢,您能夠輕鬆地從語法中構造出更復雜的代碼,這些語法將與其餘表的子查詢結果鏈接起來,或者添加其餘子查詢,如清單8所示。

 

清單8:加入一個有實表的派生表

  在清單8中,我使用了在清單7中建立的子查詢/派生表,並將它與SalesOrderHeader錶鏈接起來。經過這樣作,我能夠肯定一個不一樣的訂單日期,這是最後10次人們訂購的產品= 716

 

使用IN關鍵字進行子查詢的示例

  另外一個能夠編寫子查詢的地方,該子查詢返回一個列的多個值,當子查詢生成一個用於關鍵字的記錄集時。清單9中的代碼演示瞭如何使用子查詢將值傳遞到in關鍵字。

 

清單9:使用子查詢將值傳遞到IN關鍵字

  清單9中的代碼使用子查詢返回產品的不一樣值。包含字符「XL」的產品表。這些從子查詢返回的ProductID值而後在in關鍵字中使用,以約束從銷售中返回的行。SalesOrderDetail表。

 

在修改數據的語句中使用子查詢的例子

  到目前爲止,個人全部示例都演示瞭如何在SELECT語句的不一樣部分中使用子查詢。子查詢也能夠在插入、更新或刪除語句中使用。清單10中的代碼展現瞭如何在INSERT語句中使用子查詢。

 

清單10:插入語句中的子查詢

  在清單10的代碼中,我使用子查詢來計算插入到列MaxOrderDate中的值。這僅僅是如何在INSERT語句中使用子查詢的一個示例。請記住,子查詢也能夠在UPDATE/DELETE語句中使用。

 

子查詢與鏈接之間的性能考慮

  若是你讀過微軟生產的「子查詢基礎」文檔(http://technet.microsoft.com/en-us/library/ms189575(v=sql.105).aspx)

而後,您可能遇到了關於包含子查詢的語句的性能的語句:

「在transact - sql中,包含子查詢和語義等價的語句之間一般沒有性能差別。」

爲了比較使用子查詢和不使用子查詢的查詢的性能,我將重寫清單3中的子查詢以使用鏈接操做。清單11顯示了我從新編寫的JOIN查詢,它至關於清單3中的查詢。

 

清單11:鏈接查詢,與清單3中的查詢等效

  爲了比較清單3中使用子查詢的查詢的性能和使用JOIN的清單11中的查詢,我將使用清單12中的代碼運行兩個查詢。

 

清單12:測試清單3和清單4的性能的代碼

  在運行清單12中的代碼後,我查看了由「SET STATISTICS」語句生成的消息。經過查看統計數據,我發現兩個查詢對SalesOrderDetail表有3,309個邏輯讀取,2個邏輯讀針對產品表,每一個都使用31毫秒的CPU。另外,我回顧了爲這兩個查詢建立的SQL Server的執行計劃。我發現SQL Server對這兩種狀況都產生了相同的執行計劃。所以,在個人狀況下使用子查詢或鏈接查詢產生等價的性能,就像微軟所記錄的那樣。

 

總結

  子查詢是嵌入另外一個transact - sql語句的SELECT語句。子查詢能夠獨立於外部查詢運行,所以有時被稱爲獨立查詢。請記住,每當有一個子查詢替表明達式時,或者它與比較運算符一塊兒使用,它只能返回單個列和值。一般可使用JOIN邏輯重寫子查詢。子查詢是幫助您構建更復雜的transact - sql語句以知足業務需求的強大工具。

 

問題和回答

 

在本節中,您能夠經過回答如下問題來回顧您如何理解使用子查詢概念。

問題1:

 

完成這個句子「子查詢是在另外一個transact - sql語句中選擇語句,它是_____________________」。

•不能獨立於完整的查詢運行。

•引用來自外部查詢的列。

•當獨立於外部查詢運行時,它將返回結果。

 

問題2:

子查詢什麼時候只須要返回一個列和值(選擇全部應用程序)?

•當子查詢在FROM子句中使用時

•當子查詢在in子句中使用時

•在表達式中使用子查詢

•當子查詢與比較運算符一塊兒使用時

 

問題3:

 

WHERE子句中使用子查詢的transact - sql語句老是比不包含子查詢(TrueFalse)的等價查詢執行速度慢。

•真

•假

 

回答:

問題1:

正確的答案是c。子查詢能夠獨立於外部查詢運行,它將返回結果。它不須要來自外部查詢的任何列,若是它有來自外部查詢的列,則稱爲相關子查詢。

 

問題2:

正確的答案是cd。子查詢須要返回一個列值,當它用做表達式時,或者在比較操做中。當在關鍵字中使用子查詢時,它能夠爲一列返回一個或多個值。若是在FROM子句中使用子查詢,它只返回一個列和一個值,但它也能夠返回多個列和值。

 

問題3:

正確的答案是錯誤的。SQL Server優化器很是聰明,極可能會爲兩個等價查詢計算相同的執行計劃。若是一個查詢的執行計劃包含一個子查詢,而沒有子查詢的查詢的執行計劃最終都有相同的執行計劃,那麼這兩個查詢將具備相同的性能。

 

連接:http://www.sqlservercentral.com/articles/Stairway+Series/104517/

相關文章
相關標籤/搜索