翻译:通向T-SQL的阶梯:超越基础水平3:建立相关子查询
原文鏈接:http://www.sqlservercentral.com/articles/Stairway+Series/105972/ ? 原文作者:Gregory Larsen
該系列
本文是樓梯系列的一部分:通向T-SQL的階梯:超越基礎(chǔ)水平
從他的t - sql DML樓梯后,格雷戈里·拉森涵蓋了更高級(jí)的子查詢等方面的t - sql語(yǔ)言。
在2級(jí)樓梯我討論了如何使用數(shù)據(jù)庫(kù)引擎執(zhí)行子查詢的sql語(yǔ)句。 這樓梯水平將擴(kuò)大在子查詢主題討論類型的子查詢稱為相關(guān)subquery。 我將探索什么是相關(guān)子查詢,以及它是如何不同于正常的子查詢。 另外我將提供你一些Transaction-SQL語(yǔ)句的例子超越基本知識(shí)和使用相關(guān)子查詢來(lái)幫助識(shí)別行返回的結(jié)果集,以滿足復(fù)雜的業(yè)務(wù)需求。
相關(guān)子查詢是什么?
在2級(jí)樓梯我們了解到一個(gè)正常的子查詢只是一個(gè)SELECT語(yǔ)句在數(shù)據(jù)庫(kù)引擎執(zhí)行另一個(gè)sql語(yǔ)句,子查詢可以返回結(jié)果,如果獨(dú)立運(yùn)行的外部查詢。 相關(guān)子查詢是一種外的子查詢,不能獨(dú)立運(yùn)行查詢,因?yàn)樗粋€(gè)或多個(gè)列從外部查詢。 相關(guān)子查詢,就像一個(gè)正常的子查詢,有時(shí)被稱為內(nèi)部查詢。 如果相關(guān)子查詢(內(nèi)部查詢)獨(dú)立運(yùn)行的外部查詢將返回一個(gè)錯(cuò)誤。 因?yàn)閮?nèi)部查詢的執(zhí)行取決于價(jià)值觀從外部查詢,它被稱為相關(guān)子查詢。
相關(guān)子查詢可能多次執(zhí)行。 它將為每個(gè)選定的候選人行運(yùn)行一次外層查詢。 每個(gè)候選人一行的列值將用于供應(yīng)值外查詢中的列內(nèi)的每個(gè)執(zhí)行相關(guān)子查詢。 最后聲明,包含一個(gè)相關(guān)子查詢的結(jié)果將基于每個(gè)執(zhí)行相關(guān)子查詢的結(jié)果。
樣本數(shù)據(jù)的相關(guān)子查詢的例子
為了演示如何使用相關(guān)子查詢我需要一些測(cè)試數(shù)據(jù)。 而不是創(chuàng)建我自己的測(cè)試數(shù)據(jù),我將使用一個(gè)示例AdventureWorks2008R2數(shù)據(jù)庫(kù)。 如果你想跟隨并運(yùn)行在您的環(huán)境中我的例子你可以下載AdventureWorks2008R2數(shù)據(jù)庫(kù)從這里:http://msftdbprodsamples.codeplex.com/releases/view/93587
相關(guān)子查詢的WHERE子句的例子
展示相關(guān)子查詢的WHERE子句使用假設(shè),我想按順序確定購(gòu)買(mǎi)了超過(guò)70件的顧客的ID。 完成這個(gè)需求我可以運(yùn)行清單1中的代碼。
SELECT CustomerID FROM Sales.SalesOrderHeader OH WHERE (SELECT COUNT(*) FROM Sales.SalesOrderDetail WHERE SalesOrderID = OH.SalesOrderID) > 70;清單1:相關(guān)子查詢的WHERE子句
當(dāng)我運(yùn)行清單1中的代碼報(bào)告1中得到的輸出。 CustomerID ----------- 29712 29722 30048 30107
報(bào)告1:運(yùn)行清單1中的代碼時(shí)返回結(jié)果
如果你檢查代碼在清單1中您將看到我約束,通過(guò)使用相關(guān)子查詢。 括號(hào)內(nèi)的子查詢的代碼我已經(jīng)提取了相關(guān)子查詢代碼與清單1和清單2中把它。
SELECT COUNT(*) FROM Sales.SalesOrderDetail WHERE SalesOrderID = OH.SalesOrderID清單2:子查詢代碼在清單1中
如果我運(yùn)行清單2中的代碼將會(huì)發(fā)現(xiàn)我得到一個(gè)錯(cuò)誤顯示在報(bào)告2。
Msg 4104, Level 16, State 1, Line 3 The multi-part identifier "OH.SalesOrderID " could not be bound.報(bào)告2:運(yùn)行時(shí)錯(cuò)誤代碼在清單2中
我得到報(bào)告2所示的錯(cuò)誤,因?yàn)橄嚓P(guān)子查詢列包含一個(gè)引用哦。 SalesOrderID列從外部查詢。 因?yàn)樗邢嚓P(guān)子查詢引用一個(gè)或多個(gè)列外查詢不能獨(dú)立地運(yùn)行它們的外層查詢與之相關(guān)的。 你不能獨(dú)立運(yùn)行子查詢整個(gè)transact - sql語(yǔ)句的區(qū)分在一個(gè)正常的子查詢相關(guān)子查詢。
這里給出的例子是一個(gè)非常簡(jiǎn)單的例子在WHERE子句中使用相關(guān)子查詢。 希望通過(guò)這樣一個(gè)簡(jiǎn)單的例子是很容易理解的區(qū)別正常的子查詢和相關(guān)子查詢。 典型相關(guān)子查詢可能更加復(fù)雜。 此外,記住可能有其他方法來(lái)滿足您的業(yè)務(wù)需求不相關(guān)子查詢。
正如你所看到的寫(xiě)相關(guān)子查詢非常類似于一個(gè)正常的子查詢,但你不能獨(dú)立于外部查詢運(yùn)行相關(guān)子查詢。
相關(guān)子查詢的例子HAVING子句
有些時(shí)候你可能需要限制條款由外層查詢不同的值。 這是當(dāng)你可以使用子查詢相關(guān)條款。 假設(shè)你要編寫(xiě)一個(gè)查詢,計(jì)算退稅金額的客戶購(gòu)買(mǎi)了價(jià)值超過(guò)150000美元稅收在2008年前的產(chǎn)品。 清單3中的代碼計(jì)算退稅金額為那些有價(jià)值的客戶通過(guò)使用相關(guān)子查詢的條款。
SELECT Outer_H.[CustomerID] , SUM(Outer_H.[SubTotal]) AS TotalPurchase, SUM(Outer_H.[SubTotal]) * .10 AS Rebate FROM [Sales].[SalesOrderHeader] AS Outer_H WHERE YEAR(Outer_H.[OrderDate]) = '2008' GROUP BY Outer_H.[CustomerID] HAVING (SELECT SUM(Inner_H.[SubTotal]) FROM [Sales].[SalesOrderHeader] AS Inner_HWHERE Inner_H.[CustomerID] = Outer_H.[CustomerID]AND YEAR(Inner_H.[OrderDate]) = '2008') > 150000 ORDER BY Rebate DESC;清單3:相關(guān)子查詢?cè)跅l款
當(dāng)我運(yùn)行清單5中的代碼報(bào)告3中得到結(jié)果。
CustomerID TotalPurchase Rebate ----------- --------------------- --------------------------------------- 29923 220496.658 22049.665800 29641 210647.4929 21064.749290 29617 187964.844 18796.484400 29913 186387.5613 18638.756130 29818 179916.2877 17991.628770 29940 175358.3954 17535.839540 29987 172169.4612 17216.946120 29736 157700.6034 15770.060340 29995 156984.5148 15698.451480 29770 151824.9944 15182.499440報(bào)告3:運(yùn)行清單3的結(jié)果
在清單3中使用的相關(guān)子查詢代碼CustomerID外GROUP BY子句的查詢相關(guān)子查詢。 相關(guān)子查詢會(huì)為每一行執(zhí)行一次返回的GROUP BY子句。 這允許有條款計(jì)算每個(gè)產(chǎn)品的總量CustomerID從外部查詢的值而得到的小計(jì)列在每個(gè)SalesOrderHeader記錄相關(guān)的記錄CustomerID從外部查詢。 清單3中的transact - sql語(yǔ)句,只返回一行CustomerID在購(gòu)買(mǎi)了超過(guò)150000美元的產(chǎn)品。
一個(gè)更新語(yǔ)句的例子,其中包含相關(guān)子查詢
相關(guān)子查詢不僅可以用于使用SELECT語(yǔ)句返回一個(gè)結(jié)果集。 您也可以使用它們?cè)赟QL服務(wù)器更新數(shù)據(jù)表。 為了證明這一點(diǎn),我首先會(huì)生成一些測(cè)試數(shù)據(jù)下邊表,通過(guò)使用清單4中的代碼
?
USE tempdb; GO SET NOCOUNT ON; CREATE TABLE CarInventory ( ID int identity, CarName varchar(50), VIN varchar(50), StickerPrice decimal (7,2), InvoicePrice decimal (7,2)); GO INSERT INTO CarInventory VALUES ('Explorer','EXP2014123456A',46198.45,38201.87), ('Explorer','EXP2014123493A',47129.98, 38201.87), ('Grand Cherokee','JGC20141234345X',41678.45,36201.86), ('Grand Cherokee','JGC20141234556W',44518.31,36201.86), ('Pathfinder','NPF2014987365A',32587.73,28917.10), ('Pathfinder','NPF2014239657B',33577.54,28917.10), ('Pathfinder','NPF2014098587C',35876.12,28917.10), ('Tahoe','TAH201409674A',52001.08,46000.01);清單4:代碼來(lái)創(chuàng)建和填充測(cè)試表
清單4中的代碼創(chuàng)建了一個(gè)CarInventory表,然后填充用八行代表汽車(chē)目前在庫(kù)存。
定期銷售經(jīng)理喜歡看到他InvoicePriceRatio通過(guò)運(yùn)行清單5中的查詢
SELECT CarName, InvoicePrice/StickerPrice*100.0 AS InvoicePriceRatio FROM CarInventory;清單5:InvoicePriceRatio查詢
當(dāng)經(jīng)理運(yùn)行該查詢,她注意到有許多類似的汽車(chē)一樣InvoicePrice數(shù)量有不同InvoicePriceRatio值。 最大化發(fā)票標(biāo)價(jià)比她問(wèn)她的IT支持編寫(xiě)一個(gè)查詢,該查詢將更新StickerPrice在她所有的汽車(chē)每輛車(chē)相同CarName?有相同的價(jià)值InvoicePriceRatio。 她希望這家伙來(lái)設(shè)置StickerPrice相同的值作為最高標(biāo)價(jià)CarName。 這樣所有的汽車(chē)一樣CarName都有相同的價(jià)值StickerPrice價(jià)值。 完成這個(gè)更新的CarInventory表,這家伙運(yùn)行清單6中的transact - sql語(yǔ)句,其中包含相關(guān)子查詢。
UPDATE CarInventory SET StickerPrice = (SELECT MAX(StickerPrice) FROM CarInventory Inner_CI WHERE Inner_CI.CarName = Outer_CI.CarName) FROM CarInventory Outer_CI;清單6:相關(guān)子查詢來(lái)更新CarInventory最大標(biāo)價(jià)
清單8中的代碼使用CarName從外部查詢的相關(guān)子查詢來(lái)確定最大StickerPrice為每一個(gè)獨(dú)特的CarName。 這個(gè)最大StickerPrice然后使用相關(guān)子查詢中找到的值來(lái)更新StickerPrice值為每個(gè)CarInventory有相同的記錄CarName。
相關(guān)子查詢的性能注意事項(xiàng)
有些性能考慮你應(yīng)該意識(shí)到寫(xiě)作時(shí)transact - sql語(yǔ)句包含相關(guān)子查詢。 性能不是壞當(dāng)外層查詢包含一個(gè)小的行數(shù)。 但當(dāng)外層查詢包含大量的行不規(guī)模從性能角度來(lái)看。 這是因?yàn)橄嚓P(guān)子查詢中的每個(gè)候選人需要執(zhí)行行外部查詢。 因此,當(dāng)外部查詢包含越來(lái)越多的候選人行相關(guān)子查詢多次執(zhí)行,因此transact - sql語(yǔ)句將需要更長(zhǎng)的時(shí)間。 如果你發(fā)現(xiàn)你的相關(guān)子查詢transact - sql語(yǔ)句的性能沒(méi)有達(dá)到您的需求,那么您應(yīng)該尋找替代解決方案,比如使用一個(gè)內(nèi)部或外部連接操作的查詢,或返回一個(gè)小數(shù)量的候選人的行從外部查詢。
總結(jié)
相關(guān)子查詢是一種內(nèi)在的查詢,包括一個(gè)或多個(gè)列從外部查詢。 相關(guān)子查詢是每個(gè)外部的候選人行執(zhí)行一次查詢。 因?yàn)橄嚓P(guān)子查詢包含一個(gè)列外查詢不能獨(dú)立運(yùn)行的外部查詢。 相關(guān)子查詢的地方,雖然沒(méi)有很好地?cái)U(kuò)展從性能角度來(lái)看當(dāng)有大量的候選人中確定行外部查詢。
問(wèn)題和答案
在本節(jié)中,您可以檢查你如何理解相關(guān)子查詢的概念通過(guò)回答下列問(wèn)題。
問(wèn)題1
編寫(xiě)相關(guān)子查詢時(shí)需要___________________。 (填入空白)
1、一個(gè)或多個(gè)列的內(nèi)部查詢用于限制相關(guān)子查詢的結(jié)果。
2、一個(gè)或多個(gè)列的內(nèi)部查詢所使用的選擇列表相關(guān)子查詢。
3、一個(gè)或多個(gè)列從外部查詢用于限制相關(guān)子查詢的結(jié)果。
4、一個(gè)或多個(gè)列從外部查詢所使用的選擇列表相關(guān)子查詢。
問(wèn)題2
選擇所有的以下相關(guān)子查詢語(yǔ)句,是正確的
1、隨著候選人的行數(shù)的增加性能數(shù)據(jù)庫(kù)引擎執(zhí)行的sql語(yǔ)句,其中包含一個(gè)相關(guān)子查詢得到改善。
2、每個(gè)候選人的相關(guān)子查詢會(huì)執(zhí)行一次行從外部查詢。
3、相關(guān)子查詢會(huì)引用一個(gè)或多個(gè)列的內(nèi)部查詢。
4、當(dāng)使用子查詢相關(guān)條款內(nèi)查詢將對(duì)每個(gè)候選人行執(zhí)行一次返回的GROUP by子句。
問(wèn)題3:
相關(guān)子查詢就像一個(gè)正常的子查詢,和相關(guān)子查詢可以運(yùn)行獨(dú)立于整個(gè)transact - sql語(yǔ)句(真或假)。
答案:
問(wèn)題1:
正確答案是c。相關(guān)子查詢需要的一個(gè)或多個(gè)列外查詢相關(guān)子查詢語(yǔ)句中使用。 這些外列引用替換為值在執(zhí)行每個(gè)候選人行相關(guān)子查詢。
問(wèn)題2:
正確答案是b和d是不正確的,因?yàn)殡S著候選人的行數(shù)的增加相關(guān)子查詢被多次執(zhí)行,和數(shù)據(jù)庫(kù)引擎執(zhí)行的sql語(yǔ)句的性能惡化。 c是錯(cuò)誤的,因?yàn)橄嚓P(guān)子查詢必須包含一個(gè)或多個(gè)行從外部查詢,而不是內(nèi)在的查詢。
問(wèn)題3:
正確的答案是b。如果你嘗試運(yùn)行數(shù)據(jù)庫(kù)引擎執(zhí)行完整的sql語(yǔ)句的獨(dú)立相關(guān)子查詢,相關(guān)子查詢語(yǔ)句將失敗。
轉(zhuǎn)載于:https://www.cnblogs.com/705xinguan/p/7873382.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的翻译:通向T-SQL的阶梯:超越基础水平3:建立相关子查询的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 准确率(Accuracy), 精确率(P
- 下一篇: sqlserver服务启动后停止,传递给