SQL中的关联子查询
目錄
關(guān)聯(lián)查詢
例子
分解相關(guān)的嵌套查詢
與不同的表一起使用
關(guān)聯(lián)子查詢與內(nèi)部聯(lián)接
哪個更快?
哪個更容易閱讀?
哪一個更好?
HAVING子句中的關(guān)聯(lián)子查詢
在本文中,我們將查看幾個示例并將關(guān)聯(lián)子查詢與連接進行比較。
關(guān)聯(lián)子查詢用于將內(nèi)部查詢的條件與外部查詢中的值聯(lián)系起來。它們是避免“硬編碼”值的強大技術(shù)。在本文中,查看幾個示例并將關(guān)聯(lián)子查詢與連接進行比較。
本課的所有示例均基于Microsoft SQL Server Management Studio和AdventureWorks2012數(shù)據(jù)庫。
關(guān)聯(lián)查詢
有一些方法可以將外部查詢的值合并到子查詢的子句中。這些類型的查詢稱為關(guān)聯(lián)子查詢,因為子查詢的結(jié)果以某種形式連接到外部查詢中的值。它們有時稱為同步查詢。
如果您不知道相關(guān)的含義,請查看Google的以下定義:
關(guān)聯(lián):“具有相互關(guān)系或聯(lián)系,其中一件事影響或依賴于另一件事。”?(google)
關(guān)聯(lián)子查詢的典型用法是在內(nèi)部查詢的WHERE子句中使用外部查詢的列之一。在許多情況下,您希望將內(nèi)部查詢限制為數(shù)據(jù)子集,這是常識。
例子
我們將提供一個相關(guān)的子查詢示例,通過報告每個子查詢SalesOrderDetail LineTotal,而Average LineTotal代表整體Sales Order。
此請求與我們之前的示例有很大不同,因為我們計算的平均值因每個銷售訂單而異。
這就是關(guān)聯(lián)子查詢發(fā)揮作用的地方。我們可以使用外部查詢中的值并將其合并到子查詢的過濾條件中。
讓我們看看我們?nèi)绾斡嬎闫骄€總數(shù)。為此,我整理了一個插圖,顯示了帶有子查詢的SELECT語句。
進一步闡述圖表。該SELECT語句由兩部分組成,外部查詢和子查詢。外部查詢用于檢索所有SalesOrderDetail行。子查詢用于查找和匯總特定SalesOrderID的銷售訂單詳細信息行。
如果我要表達我們將要采取的步驟,我會將它們總結(jié)為:
您可以在數(shù)據(jù)庫中運行的AdventureWork2012查詢是:
SELECT SalesOrderID,SalesOrderDetailID,LineTotal,(SELECT AVG(LineTotal)FROM Sales.SalesOrderDetailWHERE SalesOrderID = SOD.SalesOrderID)AS AverageLineTotal FROM Sales.SalesOrderDetail SOD以下是查詢的結(jié)果:
有幾點需要指出。
分解相關(guān)的嵌套查詢
現(xiàn)在讓我們嘗試使用SQL將其分解。
首先,假設(shè)我們將獲得我們的示例SalesOrderDetailID?20。對應(yīng)的SalesOrderID是43661。
要獲得該項的LineTotal平均值很容易:
SELECT AVG(LineTotal) FROM Sales.SalesOrderDetail WHERE SalesOrderID = 43661這將返回值2181.765240。
現(xiàn)在我們有了平均值,我們可以將它插入到我們的查詢中:
SELECT SalesOrderID,SalesOrderDetailID,LineTotal,<span style="color: #ff0000;">2181.765240 AS AverageLineTotal FROM Sales.SalesOrderDetail WHERE SalesOrderDetailID = 20使用子查詢,這變成:
SELECT SalesOrderID,SalesOrderDetailID,LineTotal,(SELECT AVG(LineTotal)FROM Sales.SalesOrderDetailWHERE SalesOrderID = 43661) AS AverageLineTotal FROM Sales.SalesOrderDetail WHERE SalesOrderDetailID = 20最后的查詢是:
SELECT SalesOrderID,SalesOrderDetailID,LineTotal,(SELECT AVG(LineTotal)FROM Sales.SalesOrderDetail WHERE SalesOrderID = SOD.SalesOrderID) AS AverageLineTotal FROM Sales.SalesOrderDetail AS SOD與不同的表一起使用
關(guān)聯(lián)子查詢,或者就此而言,任何子查詢,可以使用與外部查詢不同的表。當(dāng)您使用“父”表時,這可能會派上用場,例如SalesOrderHeader,并且您希望在結(jié)果中包含子行的摘要,例如來自SalesOrderDetail。
讓我們返回銷售訂單明細行的OrderDate、TotalDue和數(shù)量。為此,我們可以使用下圖來了解我們的方位:
為此,我們將在SELECT語句中包含一個關(guān)聯(lián)子查詢以返回SalesOrderDetail行數(shù)的COUNT。我們將通過過濾外部查詢的SalesOrderID來確保計算正確的SalesOrderDetail項。
這是最后的SELECT聲明:
SELECT SalesOrderID,OrderDate,TotalDue,(SELECT COUNT(SalesOrderDetailID)FROM Sales.SalesOrderDetailWHERE SalesOrderID = SO.SalesOrderID) as LineCount FROM Sales.SalesOrderHeader SO結(jié)果是:
此示例需要注意的一些事項是:
- 子查詢從與外部查詢不同的表中選擇數(shù)據(jù)。
- 我使用表和列別名來更容易閱讀SQL和結(jié)果。
- 請務(wù)必仔細檢查您的where子句!如果您忘記在子查詢WHERE子句中包含表名或別名,則不會關(guān)聯(lián)查詢。
關(guān)聯(lián)子查詢與內(nèi)部聯(lián)接
重要的是要了解您可以使用子查詢或聯(lián)接獲得相同的結(jié)果。盡管兩者都返回相同的結(jié)果,但每種方法都有優(yōu)點和缺點!
考慮最后一個例子,我們?yōu)?/span>SalesHeader項計算項的行。
SELECT SalesOrderID,OrderDate,TotalDue,(SELECT COUNT(SalesOrderDetailID)FROM Sales.SalesOrderDetail WHERE SalesOrderID = SO.SalesOrderID) as LineCount FROM Sales.SalesOrderHeader SO可以使用INNER JOIN和GROUP BY來完成相同的查詢:
SELECT SO.SalesOrderID,OrderDate,TotalDue,COUNT(SOD.SalesOrderDetailID) as LineCount FROM Sales.SalesOrderHeader SOINNER JOIN Sales.SalesOrderDetail SODON SOD.SalesOrderID = SO.SalesOrderID GROUP BY SO.SalesOrderID, OrderDate, TotalDue哪個更快?
您會發(fā)現(xiàn)許多人會說要避免子查詢,因為它們速度較慢。他們會爭辯說,關(guān)聯(lián)子查詢必須為外部查詢中返回的每一行“執(zhí)行”一次,而INNER JOIN唯一的子查詢必須通過數(shù)據(jù)。
我呢?我說檢查查詢計劃。我對上面的兩個例子都遵循了自己的建議,發(fā)現(xiàn)計劃是一樣的!
這并不是說如果有更多數(shù)據(jù),計劃就會改變,但我的觀點是你不應(yīng)該只是做出假設(shè)。大多數(shù)SQL DBMS優(yōu)化器都非常擅長找出執(zhí)行查詢的最佳方法。他們將采用您的語法,例如子查詢或INNER JOIN,并使用它們來創(chuàng)建實際的執(zhí)行計劃。
哪個更容易閱讀?
根據(jù)您的習(xí)慣,您可能會發(fā)現(xiàn)該INNER JOIN示例比關(guān)聯(lián)查詢更易于閱讀。就個人而言,在這個例子中,我喜歡關(guān)聯(lián)子查詢,因為它看起來更直接。我更容易看到正在計算的內(nèi)容。
在我看來,INNER JOIN是不那么直接的。首先,您必須看到所有銷售明細行都被返回然后匯總。在您閱讀整個聲明之前,您不會真正明白這一點。
哪一個更好?
讓我知道你的想法。我想聽聽您是否更愿意使用關(guān)聯(lián)子查詢或INNER JOIN示例。
HAVING子句中的關(guān)聯(lián)子查詢
與任何其他子查詢一樣,HAVING子句中的子查詢可以與外部查詢中的字段相關(guān)聯(lián)。
假設(shè)我們進一步按婚姻狀況對職位進行分組,并且只想保留那些休假時間大于相應(yīng)整體婚姻狀況的職位和軍人身份的組合?
換句話說,我們想回答一個類似于“已婚會計師的平均剩余假期是否比一般已婚員工多?”的問題?
找出答案的一種方法是使用以下查詢:
SELECT JobTitle,MaritalStatus,AVG(VacationHours) FROM HumanResources.Employee AS E GROUP BY JobTitle, MaritalStatus HAVING AVG(VacationHours) > (SELECT AVG(VacationHours)FROM HumanResources.EmployeeWHERE HumanResources.Employee. MaritalStatus =E.MaritalStatus)有幾點需要指出。首先,請注意我在外部查詢中將其Employee別名為“E”。這允許我在內(nèi)部查詢中引用外部表。
此外,對于關(guān)聯(lián)查詢,只有在GROUP BY中使用的字段才能在內(nèi)部查詢中使用。例如,對于kicks和grins,我嘗試替換MaritalStatus為Gender并得到一個錯誤。
SELECT JobTitle,MaritalStatus,AVG(VacationHours) FROM HumanResources.Employee AS E GROUP BY JobTitle, MaritalStatus HAVING AVG(VacationHours) > (SELECT AVG(VacationHours)FROM HumanResources.EmployeeWHERE HumanResources.Employee. Gender = E. Gender)是一個損壞的查詢。如果您嘗試運行它,您將收到以下錯誤:
Column ‘HumanResources.Employee.Gender’ is invalid in the HAVING clause because it is not contained in either an aggregate function or the GROUP BY clause.本文最初發(fā)布于Correlated Subqueries in SQL - Essential SQL
https://www.codeproject.com/Articles/5326767/Correlated-Subqueries-in-SQL
總結(jié)
以上是生活随笔為你收集整理的SQL中的关联子查询的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图像增强学习笔记(三) | 图像锐化
- 下一篇: SQL子查询中SOME、ANY、ALL关