原文連接:http://www.sqlservercentral.com/articles/Stairway+Series/104517/sql
經過格雷戈裏·拉森,2016/01/01(第一次出版:2014/01/29)數據庫
在某些時候當你開始建立更復雜的SQL代碼,超越基本transact - SQL語句,您可能會發現須要限制你的查詢使用其餘SELECT語句的結果。 當你在父母transact - sql語句嵌入一個SELECT語句,這些嵌入的SELECT語句被稱爲子查詢,或相關子查詢。 在本層的樓梯的基本內容外,我將討論子查詢的不一樣方面,在將來我將討論相關子查詢。sqlserver
子查詢是一個SELECT語句是包含在數據庫引擎執行另外一個sql語句。 可使用子查詢可使用任何一個表達式。 許多子查詢返回一列值,由於他們結合使用比較運算符(=,! =、<、< =、>、> =),或者一個表達式。 當不使用子查詢表達式或比較運算符能夠返回多個值。 此外,子查詢能夠返回多個列和價值觀在FROM子句中使用或與關鍵字的存在。性能
數據庫引擎執行子查詢是容易被髮如今一個sql語句,由於它將SELECT語句包含在圓括號中。 因爲數據庫引擎執行子查詢包含在一個sql語句查詢一般被稱爲內部查詢。 而transact - sql語句包含子查詢被稱爲外部查詢。 子查詢的另外一個特色是它能夠獨立運行的外部查詢和運行沒有錯誤,並可能返回的一組行,或一個空行。測試
另外一種形式的子查詢是相關子查詢。 但相關子查詢不能獨立運行的外部交易的SQL語句。 相關子查詢使用列或列從外部查詢限制相關子查詢返回的結果。 這是對這篇文章的相關子查詢。 我將探索相關子查詢在之後的樓梯。優化
這裏有一些其餘的事情時要考慮使用子查詢:spa
爲了演示如何使用子查詢我須要一些測試數據。 而不是建立我本身的測試數據,我全部的例子將使用AdventureWorks2008R2數據庫。 若是你想跟隨並運行在您的環境中個人例子你能夠下載AdventureWorks2008R2數據庫從這裏:http://msftdbprodsamples.codeplex.com/releases/view/93587code
如上所述,子查詢中使用一個表達式或返回一個值比較運算符的一側必須返回一個值。 transact - sql語句中有許多不一樣的地方須要子查詢返回一個列值,就像在一個選擇列表,where子句,等等。在本節中,我將提供一系列的例子將演示使用子查詢表達式或比較運算符,以知足不一樣的業務需求。
子查詢的列列表是一個SELECT語句返回一列值的列列表放置在一個SELECT子句。 爲了演示如何使用選擇列表的子查詢假設咱們必須從一個SELECT語句產生一個結果集,如下業務需求:
知足這些需求的代碼如清單1所示。
SELECT ROW_NUMBER() OVER (ORDER BY SalesOrderID) RowNumber , (SELECT COUNT(*) FROM [Sales].[SalesOrderHeader] WHERE ModifiedDate = '2007-02-19 00:00:00.000') AS TotalOrders , * FROM [Sales].[SalesOrderHeader] WHERE OrderDate = '2007-02-19 00:00:00.000';
在這個單一transact - sql聲明中看到兩個不一樣的選擇條款。 子查詢的SELECT語句嵌入在清單1,括號中的語句。 我拿出了子查詢語句和把它在清單2中,若是您想測試來驗證它能夠獨立完成transact - sql語句的運行。
SELECT COUNT(*) FROM [Sales].[SalesOrderHeader] WHERE OrderDate = '2007-02-19 00:00:00.000'
經過這個子查詢的列列表,這Listing1 transact - sql語句可以數的數量SalesOrderHeader行,一個向數據庫「2007-02-19 00:00:00.000」和返回的信息以及詳細的行信息Sales.SalesOrderHeader有相同的記錄向數據庫價值。
有時你想開車WHERE子句條件基於一個SELECT語句的結果。 當你一個SELECT語句的WHERE子句這個SELECT語句是一個真正的子查詢。 爲了演示在WHERE子句中使用子查詢,假設你須要顯示Sales.SalesOrderDetail記錄包含購買超大長袖商標運動衫。 清單3中的代碼使用子查詢知足個人顯示要求。
SELECT * FROM [Sales].[SalesOrderDetail] WHERE ProductID = (SELECT ProductID FROM [Production].[Product] WHERE Name = 'Long-Sleeve Logo Jersey, XL');
清單3中的查詢是在右邊的條件。 這個子查詢標識一個ProductID對於一個Production.Product記錄在哪裏的名字的產品是「長袖標誌的球衣,XL。 這個子查詢容許我發現全部的Sales.SalesOrderDetail記錄,有ProductID與產品名稱相關聯的「長袖標誌的球衣,XL」。
返回的行數使用上面的條款能夠控制的一個表達式。 清單5中的代碼標識的數量Sales.SalesOrderDetail行應該返回基於子查詢的條款。
SELECT TOP (SELECT TOP 1 OrderQty FROM [Sales].[SalesOrderDetail] ORDER BY ModifiedDate) * FROM [Sales].[SalesOrderDetail] WHERE ProductID = 716;
清單4中的代碼使用OrderQty子查詢返回的值來標識的值將用於條款。 經過使用子查詢控制返回的行數,上面條款,容許您動態構建子查詢,肯定在運行時從查詢返回的行數。
爲了演示使用子查詢子句,假設你有如下業務需求:
產生一個結果集,其中包含了Sales.SalesOrderHeader.OrderDate每一個日期和訂單的數量,訂單的數量超過了訂單的數量了‘2006-05-01’。
爲了達到這個要求我開發了清單6中的查詢中使用子查詢子句。
SELECT count(*), OrderDate FROM [Sales].[SalesOrderHeader] GROUP BY OrderDate HAVING count(*) > (SELECT count(*) FROM [Sales].[SalesOrderHeader] WHERE OrderDate = '2006-05-01 00:00:00.000');
清單5中的代碼的子查詢右邊有條款和使用計數函數在子查詢來肯定訂單的數量在「2006-05-01」。
爲了演示在函數調用中使用子查詢,假設您有要求顯示之間的天數向數據庫和最大向數據庫爲每個銷售。SalesOrderHeader記錄。 清單6中的代碼知足這個需求。
SELECT SalesOrderID , OrderDate ,DATEDIFF ( dd,OrderDate ,(SELECT MAX(OrderDate) FROM [Sales].[SalesOrderHeader]) ) AS DaysBetweenOrders ,(SELECT MAX(OrderDate) FROM [Sales].[SalesOrderHeader]) AS MaxOrderDate FROM [Sales].[SalesOrderHeader];
清單6中的代碼有兩個不一樣的子查詢。 兩個子查詢返回的馬克斯向數據庫在Sales.SalesOrderHeader表。 但第一子查詢是用來傳遞一個日期DATEDIFF函數的第二個參數。
到目前爲止,我全部的例子包含子查詢只返回一個值在一個列中。 並非全部的子查詢需求。 接下來的幾個例子將使用子查詢返回多個值和/或多個列。
在FROM子句一般肯定一個表或一組表,你transact - sql語句將對運做。 每一個表提供了一組記錄您的查詢將使用來肯定最終的查詢結果集。 子查詢能夠被認爲是一個查詢,返回一組記錄,所以它能夠用於從條款就像一張桌子。 查詢我在清單7顯示瞭如何使用子查詢的FROM子句。 子查詢時FROM子句中使用子查詢的結果集生產一般被稱爲一個派生表。
SELECT SalesOrderID FROM (SELECT TOP 10 SalesOrderID FROM [Sales].[SalesOrderDetail] WHERE ProductID = 716 ORDER BY ModifiedDate DESC) AS Last10SalesOrders;
SELECT DISTINCT OrderDate FROM (SELECT TOP 10 SalesOrderID FROM [Sales].[SalesOrderDetail] WHERE ProductID = 716 ORDER BY ModifiedDate DESC) AS Last10SalesOrders JOIN [Sales].[SalesOrderHeader] AS SalesOrderHeader ON Last10SalesOrders.SalesOrderID = SalesOrderHeader.SalesOrderID ORDER BY OrderDate
在清單8中我建立的子查詢/派生表我在清單7中,加入SalesOrderHeader表。 這樣我能夠肯定OrderDate大相徑庭的最後一人命令ProductID = 716的10倍。
另外一個地方,您能夠編寫一個查詢,它返回多個值的列是當你的子查詢生成一個記錄集,使用的關鍵字。 清單9中的代碼演示瞭如何經過使用子查詢的關鍵字值。
SELECT * FROM [Sales].[SalesOrderDetail] WHERE ProductID IN (SELECT ProductID FROM [Production].[Product] WHERE Name like '%XL%');
清單9中的代碼使用子查詢返回不一樣的值ProductID從Production.Product包含字符表,有一個名稱「XL」。 這些ProductID返回值 而後子查詢中使用的關鍵字來限制返回的行Sales.SalesOrderDetail表。
前女朋友一個mple使用子查詢在一份聲明中,修改數據
目前爲止我全部的示例演示如何使用子查詢在一個SELECT語句的不一樣部分。 子查詢也可被用來在一個INSERT、UPDATE或DELETE語句。 清單10中的代碼展現瞭如何使用子查詢在一個INSERT語句。
DECLARE @SQTable TABLE ( OrderID int, OrderDate datetime, TotalDue money, MaxOrderDate datetime); -- INSERT with SubQuery INSERT INTO @SQTable SELECT SalesOrderID, OrderDate, TotalDue, (SELECT MAX(OrderDate) FROM [Sales].[SalesOrderHeader]) FROM [Sales].[SalesOrderHeader] WHERE CustomerID = 29614; -- Display Records SELECT * FROM @SQtable;
在個人代碼在清單10中,我使用子查詢計算值插入到列中MaxOrderDate。 這只是一個例子,如何在INSERT語句中使用子查詢。 記住子查詢也可被用來在一個更新和/或DELETE語句。
若是你讀過的「子查詢基本面」文檔由微軟(http://technet.microsoft.com/en-us/library/ms189575(v = sql.105). aspx),那麼您可能已經運行在這個聲明中關於性能包含子查詢的語句:
「在transact - sql,一般沒有語句之間的性能差別,包括子查詢和語義上等價版本不。」
比較查詢的性能使用子查詢和一個等價查詢不使用子查詢我重寫個人子查詢在清單3中使用鏈接操做。 清單11顯示了查詢重寫鏈接查詢,至關於我在清單3中。
SELECT SOD.* FROM [Sales].[SalesOrderDetail] AS SOD INNER JOIN [Production].[Product] AS P ON SOD.ProductID = P.ProductID WHERE P.Name = 'Long-Sleeve Logo Jersey, XL';
比較查詢的性能在清單3中使用子查詢和查詢在清單11中,使用加入我將使用清單12中的代碼運行兩個查詢。
SET STATISTICS IO ON; SET STATISTICS TIME ON; -- Listing 3 query SELECT * FROM [Sales].[SalesOrderDetail] WHERE ProductID = (SELECT ProductID FROM Production.Product WHERE Name = 'Long-Sleeve Logo Jersey, XL'); -- Listing 11 query SELECT SOD.* FROM [Sales].[SalesOrderDetail] AS SOD INNER JOIN [Production].[Product] AS P ON SOD.ProductID = P.ProductID WHERE P.Name = 'Long-Sleeve Logo Jersey, XL';
清單12:代碼清單3和清單4的測試性能
清單12中的代碼運行後我檢查生成的消息」設置統計」語句。 經過回顧統計我發現有3309個邏輯讀與查詢SalesOrderDetail表,和2邏輯讀產品表,每一個31女士的CPU使用。 另外我回顧了執行計劃,SQL Server建立這兩個查詢。 我發現SQL Server產生相同的執行計劃。 所以使用子查詢或加入查詢個人處境產生等效性能,一樣記錄了微軟。
子查詢是一個SELECT語句嵌入式數據庫引擎執行與另外一個sql語句。 外查詢的子查詢能夠獨立運行,所以有時被稱爲一個獨立的查詢。 記住,任什麼時候候你有一個查詢的一個表達式,或是使用比較運算符,它能夠只返回單個列和價值。 一般子查詢可使用加入重寫邏輯。 子查詢是一個強大的工具來幫助你創建你的數據庫引擎執行更復雜的sql語句來知足您的業務需求。
在本節中,您能夠檢查你理解如何使用子查詢概念,回答下列問題。
完成這個句子「子查詢是一個數據庫引擎執行SELECT語句在另外一個sql語句,_____________________。
何時子查詢只須要返回一個列和值(選擇全部適用)?
transact - sql語句的WHERE子句中使用子查詢老是比等效的查詢執行速度較慢,不包含子查詢(真或假)?
正確答案是c。外查詢的子查詢能夠獨立運行,它將返回結果。 它不須要任何列從外部查詢,若是有列外查詢稱爲相關子查詢。
正確答案是c和d。子查詢時須要返回一列值用做表達式,或者比較操做。 子查詢時使用的關鍵字能夠返回一個或多個值的列。 若是子查詢在FROM子句中使用它能夠返回一個列和一個值,但它也能夠返回多個列和價值觀。
正確的答案是錯誤的。 SQL Server優化器很聰明和極可能計算相同的兩個等價的查詢執行計劃。 若是一個查詢的執行計劃,其中包含子查詢和一個等價的無子查詢都獲得相同的執行計劃而後查詢都有相同的性能。