SQL Server的子查詢詳解
目錄
- 一、子查詢基礎知識
- 二、子查詢規則
- 三、限定子查詢中的列名
- 四、子查詢的多層嵌套
- 五、相關子查詢
- 六、子查詢類型
- 總結
一、子查詢基礎知識
子查詢是嵌套在SELECT、INSERT、UPDATE、DELETE語句中或另一個子查詢中的查詢。
可以在允許表達式的任何位置使用子查詢。
示例:
USE AdventureWorks2016;GOSELECT Ord.SalesOrderID, Ord.OrderDate, (SELECT MAX(OrdDet.UnitPrice) FROM Sales.SalesOrderDetail AS OrdDet WHERE Ord.SalesOrderID = OrdDet.SalesOrderID) AS MaxUnitPriceFROM Sales.SalesOrderHeader AS Ord;GO
子查詢也稱為內部查詢或內部選擇,而包含子查詢的語句也稱為外部查詢或外部選擇。
許多包含子查詢的 Transact-SQL 語句也可以表述為聯接。其他問題只能用子查詢提出。在 Transact-SQL 中,包含子查詢的語句與不包含子查詢的語義等效版本之間通常沒有性能差異。但是,在某些必須檢查是否存在的情況下,聯接會產生更好的性能。否則,必須為外部查詢的每個結果處理嵌套查詢,以確保消除重復項。在這種情況下,聯接方法將產生更好的結果。
以下示例顯示了返回相同結果集和執行計劃的子查詢和聯接:
USE AdventureWorks2016;GO/* SELECT statement built using a subquery. */SELECT [Name]FROM Production.ProductWHERE ListPrice = (SELECT ListPrice FROM Production.Product WHERE [Name] = "Chainring Bolts" );GO/* SELECT statement built using a join that returns the same result set. */SELECT Prd1.[Name]FROM Production.Product AS Prd1 JOIN Production.Product AS Prd2 ON (Prd1.ListPrice = Prd2.ListPrice)WHERE Prd2.[Name] = "Chainring Bolts";GO
嵌套在外部 SELECT 語句中的子查詢具有以下組件:
- 包含常規選擇列表組件的常規查詢。
- 包含一個或多個表或視圖名稱的常規子句。
- 可選:WHERE、GROUP BY、HAVING。
子查詢的 SELECT 查詢始終括在括號中。它不能包含 or 子句,并且只能在還指定 TOP 子句時才包含子句。
子查詢可以嵌套在外部 WHERE、HAVING、SELECT、INSERT、UPDATE、DELETE或語句的 or 子句中,也可以嵌套在另一個子查詢中。最多可以嵌套 32 個級別,但限制因可用內存和查詢中其他表達式的復雜性而異。單個查詢可能不支持嵌套多達 32 個級別。如果子查詢返回單個值,則子查詢可以出現在可以使用表達式的任何位置。
如果表僅出現在子查詢中而不出現在外部查詢中,則該表中的列不能包含在輸出(外部查詢的選擇列表)中。
包含子查詢的語句通常采用以下格式之一:
- WHERE expression [NOT] IN (subquery)
- WHERE expression comparison_operator [ANY | ALL] (subquery)
- WHERE [NOT] EXISTS (subquery)
在某些 Transact-SQL 語句中,可以像計算獨立查詢一樣計算子查詢。從概念上講,子查詢結果被替換到外部查詢中(盡管這不一定是 SQL Server 實際處理帶有子查詢的 Transact-SQL 語句的方式)。
有三種基本類型的子查詢:
對引入的列表進行操作,或者比較運算符由 INANY或ALL 修改的列表。
使用未修改的比較運算符引入,并且必須返回單個值。
是否使用EXISTS引入存在性測試。
二、子查詢規則
- 使用比較運算符引入的子查詢的選擇列表只能包含一個表達式或列名。
- 如果外部查詢的子句包含列名,則該子句必須與子查詢選擇列表中的列連接兼容。
- ntext、text 和 image 數據類型不能在子查詢的選擇列表中使用。
- 由于它們必須返回單個值,因此由未修改的比較運算符(不后跟關鍵字或)引入的子查詢不能包含 and 子句。
- 關鍵字不能與包含 的子查詢一起使用。
- 不能指定 and 子句。
- ORDER BY只有在也指定TOP時才能指定。
- 無法使用子查詢創建的視圖進行更新。
三、限定子查詢中的列名
示例:外部查詢子句中的 BusinessEntityID 列由外部查詢子句 (Sales.Store) 中的表名隱式限定。子查詢的選擇列表中對 CustomerID 的引用由子查詢子句(即 Sales.Customer 表)限定。
USE AdventureWorks2016;GOSELECT [Name]FROM Sales.StoreWHERE BusinessEntityID NOT IN (SELECT CustomerID FROM Sales.Customer WHERE TerritoryID = 5);GO
一般,語句中的列名由同一級別的子句中引用的表隱式限定。如果子查詢子句中引用的表中不存在列,則外部查詢子句中引用的表將隱式限定該列。
下面是指定這些隱式假設的查詢的外觀:
USE AdventureWorks2016;GOSELECT [Name]FROM Sales.StoreWHERE Sales.Store.BusinessEntityID NOT IN (SELECT Sales.Customer.CustomerID FROM Sales.Customer WHERE TerritoryID = 5);GO
顯式聲明表名永遠不會錯,并且始終可以使用顯式限定覆蓋有關表名的隱式假設。
四、子查詢的多層嵌套
子查詢本身可以包含一個或多個子查詢。任意數量的子查詢可以嵌套在一個語句中。
示例:查詢查找同時也是銷售人員的員工的姓名。
USE AdventureWorks2016;GOSELECT LastName, FirstNameFROM Person.PersonWHERE BusinessEntityID IN (SELECT BusinessEntityID FROM HumanResources.Employee WHERE BusinessEntityID IN(SELECT BusinessEntityID FROM Sales.SalesPerson) );GO
輸出:
最里面的查詢返回銷售人員 ID。下一個更高級別查詢使用這些銷售人員 ID 進行評估,并返回員工的聯系人 ID 號。最后,外部查詢使用聯系人 ID 查找員工的姓名。
還可以將此查詢表示為聯接:
USE AdventureWorks2016;GOSELECT LastName, FirstNameFROM Person.Person cINNER JOIN HumanResources.Employee eON c.BusinessEntityID = e.BusinessEntityIDJOIN Sales.SalesPerson sON e.BusinessEntityID = s.BusinessEntityID;GO
五、相關子查詢
可以通過執行一次子查詢并將結果值替換到外部查詢的子句中來計算許多查詢。在包含相關子查詢(也稱為重復子查詢)的查詢中,子查詢依賴于其值的外部查詢。這意味著子查詢將重復執行,外部查詢可能選擇的每一行執行一次。
示例:
USE AdventureWorks2016;GOSELECT DISTINCT c.LastName, c.FirstName, e.BusinessEntityIDFROM Person.Person AS c JOIN HumanResources.Employee AS eON e.BusinessEntityID = c.BusinessEntityIDWHERE 5000.00 IN (SELECT Bonus FROM Sales.SalesPerson sp WHERE e.BusinessEntityID = sp.BusinessEntityID) ;GO
輸出結果:
此語句中的上一個子查詢不能獨立于外部查詢進行計算。它需要 Employee.BusinessEntityID 的值,但此值會隨著 SQL Server 檢查 Employee 中的不同行而更改。 這正是計算此查詢的方式:SQL Server 通過將每行中的值替換為內部查詢來考慮將 Employee 表的每一行包含在結果中。 例如,如果 SQL Server 首先檢查 的行,則變量 Employee.BusinessEntityID 采用值 285,SQL Server 將其替換到內部查詢中。這兩個查詢示例表示具有相關子查詢的前一個示例的分解。
USE AdventureWorks2016;GOSELECT BonusFROM Sales.SalesPersonWHERE BusinessEntityID = 285;GO
結果為 0.00(沒有收到獎金,因為他們不是銷售人員),因此外部查詢的計算結果為:
USE AdventureWorks2016;GOSELECT LastName, FirstNameFROM Person.Person AS c JOIN HumanResources.Employee AS eON e.BusinessEntityID = c.BusinessEntityIDWHERE 5000 IN (0.00);GO
由于這是 false,因此 的行不包含在具有相關子查詢的上一個示例查詢的結果中。對 的行執行相同的過程。您將看到此行包含在結果中,因為包含結果。
小結:相關子查詢還可以通過在外部查詢中引用表中的列作為表值函數的參數,在子句中包含表值函數。在這種情況下,對于外部查詢的每一行,將根據子查詢計算表值函數。
六、子查詢類型
- 帶別名。
- 帶IN或NOT IN。
- 在UPDATE、DELETE 和 INSERT 語句中。
- 使用比較運算符。
- 使用 ANY、SOME 或 ALL。
- 跟 IS [NOT] DISTINCT FROM。
- 帶 EXISTS或 NOT EXISTS。
- 代替表達式。
總結
如果在子查詢中引用的列在子查詢中不存在,但存在于外部查詢的子句引用的表中,則查詢將執行而不會出錯。SQL Server 使用外部查詢中的表名隱式限定子查詢中的列。
到此這篇關于SQL Server的子查詢詳解的文章就介紹到這了,更多相關SQL Server子查詢內容請搜索以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持!
