日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

SQL Server-聚焦APPLY运算符(二十七)

發布時間:2023/12/10 数据库 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SQL Server-聚焦APPLY运算符(二十七) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

其實有些新的特性在SQL Server早就已經出現過,但是若非系統的去學習數據庫你會發現在實際項目中別人的SQL其實是比較復雜的,其實利用新的SQL Server語法會更加方便和簡潔,從本節開始我們將講述一些SQL Server中早已出現的新語法,簡短的內容,深入的理解,Always to reivew the basics。

初探APPLY運算符

APPLY運算符是一個非常強大的表運算符,但是APPLY不是標準的,相對應的標準叫做LATERAL,但是此標準并未在SQL Server中實現。像所有表運算符一樣,該運算符用于查詢的FROM子句中。APPLY運算符支持的類型是CROSS APPLY和OUTER APPLY。CROSS APPY僅僅實施一個邏輯查詢處理階段,而OUTER APPLY實施了兩個階段,APPLY運算符對兩個輸入表進行操作,第二個可以是一個表表達式,我們將APPLY兩側的表分別叫做左側表和右側表,右側表通常是一個派生表或TVF(內嵌表值函數)。CROSS APPLY運算符實施一個邏輯查詢處理階段-它將右側的表表達式應用到左側表的每一行,并生成一個組合結果集的結果表。CROSS APPLYl類似于交叉聯接中的CROSS JOIN,但是使用CROSS APPLY運算符,右側的表表達式可以對來自左側表的每一行表示一個不同的行集,這是與聯接的不同之處。當在右側使用一個派生表,并且派生表查詢中引用來自左側表的屬性,就可以實現此目標,或者是在右側使用一個內嵌TVF,可以傳遞左側的屬性作為輸入參數,同樣可以實現此目的-摘抄自SQL Server 2012基礎教程。下面我們看一個簡單的例子。

USE TSQL2012 GOSELECT C.custid, A.orderid, A.orderdate FROM Sales.Customers AS CCROSS APPLY(SELECT TOP(3) orderid, empid, orderdate, requireddate FROM Sales.Orders AS OWHERE O.custid = C.custidORDER BY orderdate DESC, orderid DESC) AS A;

上述完成的是返回每個客戶最近的3個訂單。我們可以將右側的表表達式看做是一個相關子查詢,右側的表表達式通過引用custid對來自Customers表的每一行進行處理并返回每個客戶的最近的3個訂單,是不是看起來很清爽呢,下面我們將進一步探討APPLY運算符的作用。

進一步探討APPLY運算符

上面我們看到通過相關子查詢來進行查詢顯得代碼有點丑陋,我們再來看一個例子。查詢每個單價最高的訂單,我們通過子查詢來實現。

CROSS APPLY

USE AdventureWorks2012 GOSELECT SalesOrderID,OrderDate,MaxUnitPrice =(SELECT MAX(sod.UnitPrice) FROM Sales.SalesOrderDetail sod WHERE soh.SalesOrderID = sod.SalesOrderID) FROM Sales.SalesOrderHeader AS soh

如上操作看似代碼比較簡潔也能完成我們的查詢訴求,但是我們用派生表來進行查詢又是怎樣的呢??

USE AdventureWorks2012 GOSELECT soh.SalesOrderID,soh.OrderDate,sod.max_unit_price FROM Sales.SalesOrderHeader AS soh JOIN (SELECT max_unit_price = MAX(sod.UnitPrice),SalesOrderIDFROM Sales.SalesOrderDetail AS sodGROUP BY sod.SalesOrderID ) sod ON sod.SalesOrderID = soh.SalesOrderID

此時由于兩個表完全不相關,我們需要通過GROUP BY完成再進行JOIN,代碼不是顯得非常臃腫嗎,這還是簡單的,當有多個表時就比較復雜了,導致代碼就不再具有可讀性。但是自從在SQL Server 2005中有了APPLY媽媽再也不用擔心我讀不懂復雜的代碼了,我們看看CROSS APPLY是怎樣實現的。

USE AdventureWorks2012 GOSELECT soh.SalesOrderID,soh.OrderDate,sod.max_unit_price FROM Sales.SalesOrderHeader AS soh CROSS APPLY (SELECT max_unit_price = MAX(sod.UnitPrice)FROM Sales.SalesOrderDetail AS sodWHERE soh.SalesOrderID = sod.SalesOrderID ) sod

當我們利用內部聯接時此時JOIN中的查詢是獨立的所以需要進行GROUP BY,而對于CROSS APPLY它本身就是對來自左側的表中每一行就行處理并返回,同時利用CROSS APPLY它也超越了相關子查詢,比如說我們還需要查出每個訂單的總價呢,我們利用相關子查詢需要再次嵌入SELECT子句。

SELECT SalesOrderID ,OrderDate ,MaxUnitPrice = (SELECT MAX(sod.UnitPrice) FROM Sales.SalesOrderDetail sod WHERE soh.SalesOrderID = sod.SalesOrderID),SumLineTotal = (SELECT SUM(LineTotal) FROM Sales.SalesOrderDetail sod WHERE soh.SalesOrderID = sod.SalesOrderID) FROM Sales.SalesOrderHeader AS soh

而利用CROSS APPLY只需添加集合函數SUM即可

USE AdventureWorks2012 GOSELECT soh.SalesOrderID,soh.OrderDate,sod.max_unit_price,sod.sum_line_total FROM Sales.SalesOrderHeader AS soh CROSS APPLY (SELECT max_unit_price = MAX(sod.UnitPrice),sum_line_total = SUM(sod.LineTotal)FROM Sales.SalesOrderDetail AS sodWHERE soh.SalesOrderID = sod.SalesOrderID ) sod?

OUTER APPLY

對于OUTER APPLY,如果右側的表表達式返回一個空集合,CROSS APPLY運算符不會返回相應的左側行,也就是說OUTER APPLY和在派生表上進行LEFT JOIN是等同的,如下:

SELECT soh.SalesOrderID,soh.OrderDate,sod.max_unit_price FROM Sales.SalesOrderHeader AS soh LEFT JOIN (SELECT max_unit_price = MAX(sod.UnitPrice),SalesOrderIDFROM Sales.SalesOrderDetail AS sodGROUP BY sod.SalesOrderID ) sod ON sod.SalesOrderID = soh.SalesOrderID

此時我們利用OUTER APPLY則是如下:

USE AdventureWorks2012 GOSELECT soh.SalesOrderID,soh.OrderDate,sod.max_unit_price FROM Sales.SalesOrderHeader AS soh OUTER APPLY (SELECT max_unit_price = MAX(sod.UnitPrice)FROM Sales.SalesOrderDetail AS sodWHERE soh.SalesOrderID = sod.SalesOrderID ) sod

上述對于APPLY右側表表達式是一個派生表,此時為了封裝,我們可以使用TVF內嵌表值函數來實現。其實將內嵌表值函數來代替派生表實現每個客戶最近的3個訂單。首先我們封裝一個表值函數

USE TSQL2012 GOIF OBJECT_ID('dbo.TopOrders') IS NOT NULLDROP FUNCTION dbo.TopOrders; GOCREATE FUNCTION dbo.TopOrders(@custid AS INT, @n AS INT)RETURNS TABLE AS RETURNSELECT orderid, empid, orderdate, requireddateFROM Sales.OrdersWHERE custid = @custidORDER BY orderdate DESC, orderid DESCOFFSET 0 ROWS FETCH FIRST @n ROWS ONLY; GO

接著利用CROSS APPLY進行查詢。

USE TSQL2012 GOSELECT C.custid, C.companyname, A.orderid, A.empid, A.requireddate FROM Sales.Customers AS CCROSS APPLY dbo.TopOrders(C.custid, 3) AS A;

上面我們通過封裝內嵌表值函數代替派生表使代碼更具可讀性和可維護性。到此我們可以得出一點基本結論。

APPLY運算符使用分析結論:當需要對表中的每一行進行應用時,且需要將所有結果集組合到一個結果集表中時,此時我們應該使用APPLY運算符,至于是使用CROSS APPLY還是OUTER APPLY根據場景而定,雖然APPLY右側表可以用相關子查詢或者派生表來實現,但是使得代碼臃腫和可維護性差,通過封裝內嵌表值函數來實現可以說是對右側表通過相關子查詢或者派生表來實現的完美替代者。

總結

本節我們講解了APPLY運算符中兩種類型的使用,下一節我們來分析下關于CROSS APPLY VS INNER JOIN的性能問題,同時也說明下CROSS APPLY和OUTER APPLY的應用場景。簡短的內容,深入的理解,我們下節再會。

轉載于:https://www.cnblogs.com/CreateMyself/p/6193183.html

總結

以上是生活随笔為你收集整理的SQL Server-聚焦APPLY运算符(二十七)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。