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