開窗函數 First_Value 和 Last_Value

来源:http://www.cnblogs.com/Gin-23333/archive/2016/07/12/5663307.html
-Advertisement-
Play Games

在Sql server 2012裡面,開窗函數豐富了許多,其中帶出了2個新的函數 First_Value 和 Last Value .現在來介紹一下這2個函數的應用場景. 首先分析一下First_Value(),用法是根據Partition By對數據進行分區,如果忽略Partition By ,那 ...


在Sql server 2012裡面,開窗函數豐富了許多,其中帶出了2個新的函數 First_Value 和 Last Value .現在來介紹一下這2個函數的應用場景.

首先分析一下First_Value(),用法是根據Partition By對數據進行分區,如果忽略Partition By ,那麼預設整塊數據一個區域,然後根據Order By 進行排序,取出第一個值。

;WITH CTE AS(
SELECT 1 AS ID ,'2016-06-01' AS DT,'A' AS UName,135 AS TotalAmount UNION ALL
SELECT 2 AS ID ,'2016-06-05' AS DT,'A' AS UName,148 AS TotalAmount UNION ALL
SELECT 3 AS ID ,'2016-06-02' AS DT,'B' AS UName,120 AS TotalAmount UNION ALL
SELECT 4 AS ID ,'2016-06-06' AS DT,'B' AS UName,153 AS TotalAmount UNION ALL
SELECT 5 AS ID ,'2016-06-10' AS DT,'B' AS UName,198 AS TotalAmount 
)
SELECT * ,
        FIRST_VALUE(CTE.TotalAmount) OVER (PARTITION BY CTE.UName ORDER BY CTE.ID) AS FirstDeal,
        FIRST_VALUE(CTE.DT) OVER (PARTITION BY CTE.UName ORDER BY CTE.ID) AS FirstDate
    FROM CTE

ID DT UName TotalAmount FirstDeal FirstDate
----------- ---------- ----- ----------- ----------- ----------
1 2016-06-01 A 135 135 2016-06-01
2 2016-06-05 A 148 135 2016-06-01
3 2016-06-02 B 120 120 2016-06-02
4 2016-06-06 B 153 120 2016-06-02
5 2016-06-10 B 198 120 2016-06-02

在這個場景裡面,我求出了根據用戶名稱(UName)來進行分區,根據ID進行一個排序,求出每個用戶第一次購買商品的時間以及交易的金額。如果不使用First_Value 我們也可以換另外一種寫法

;WITH CTE AS(
SELECT 1 AS ID ,'2016-06-01' AS DT,'A' AS UName,135 AS TotalAmount UNION ALL
SELECT 2 AS ID ,'2016-06-05' AS DT,'A' AS UName,148 AS TotalAmount UNION ALL
SELECT 3 AS ID ,'2016-06-02' AS DT,'B' AS UName,120 AS TotalAmount UNION ALL
SELECT 4 AS ID ,'2016-06-06' AS DT,'B' AS UName,153 AS TotalAmount UNION ALL
SELECT 5 AS ID ,'2016-06-10' AS DT,'B' AS UName,198 AS TotalAmount 
)
SELECT * 
    FROM CTE a
        CROSS APPLY(SELECT TOP 1 a.TotalAmount AS FirstDeal,DT AS FirstDate FROM CTE WHERE a.UName = CTE.UName ORDER BY CTE.ID) AS b

--或者改寫成這種形式

;WITH CTE AS(
SELECT 1 AS ID ,'2016-06-01' AS DT,'A' AS UName,135 AS TotalAmount UNION ALL
SELECT 2 AS ID ,'2016-06-05' AS DT,'A' AS UName,148 AS TotalAmount UNION ALL
SELECT 3 AS ID ,'2016-06-02' AS DT,'B' AS UName,120 AS TotalAmount UNION ALL
SELECT 4 AS ID ,'2016-06-06' AS DT,'B' AS UName,153 AS TotalAmount UNION ALL
SELECT 5 AS ID ,'2016-06-10' AS DT,'B' AS UName,198 AS TotalAmount 
)
SELECT a.*,b.TotalAmount AS FirstDeal,b.DT AS FirstDate
    FROM CTE a
        LEFT JOIN CTE b ON a.UName = b.UName AND NOT EXISTS(SELECT * FROM CTE WHERE b.UName = UName AND DT < b.DT)

在這三種寫法裡面,查詢的結果是一致的,燃鵝從查詢分析器分析的分析來看,查詢性能,使用First_Value 的效率最高,not exists 的效率其次,使用Cross Apply 效率最低。

但是這隻是從查詢這麼少量的測試數據反饋出來的結果,如果具體的場景需要應用,最好是結合實際情況看實際的查詢計劃來得出最適當的查詢效果。

 

然後說下 Last_Value() 的用法,雖然說First_Value 和 Last_Value 一看就想兩兄弟。但是!用起來真不是這樣的一回事啊!

如果根據First_Value 的解釋,那麼Last_Value 就是根據Partition進行分區,根據Order By 進行排序返回最後的一個值。想我是這樣想的,但是操作起來就不是這麼一回事了。

;WITH CTE AS(
SELECT 1 AS ID ,'2016-06-01' AS DT,'A' AS UName,135 AS TotalAmount UNION ALL
SELECT 2 AS ID ,'2016-06-05' AS DT,'A' AS UName,148 AS TotalAmount UNION ALL
SELECT 3 AS ID ,'2016-06-02' AS DT,'B' AS UName,120 AS TotalAmount UNION ALL
SELECT 4 AS ID ,'2016-06-06' AS DT,'B' AS UName,153 AS TotalAmount UNION ALL
SELECT 5 AS ID ,'2016-06-10' AS DT,'B' AS UName,198 AS TotalAmount 
)
SELECT * ,
        LAST_VALUE(CTE.TotalAmount) OVER ( PARTITION BY CTE.UName ORDER BY CTE.DT) AS LR
    FROM CTE


ID          DT         UName TotalAmount LR
----------- ---------- ----- ----------- -----------
1           2016-06-01 A     135         135
2           2016-06-05 A     148         148
3           2016-06-02 B     120         120
4           2016-06-06 B     153         153
5           2016-06-10 B     198         198

 

咦!?說好的根據 UName 進行分組,然後再DT進行排序區最後一個價格呢??完全不是這樣子啊!!

對,這才是Last_Value的用法,實際上。在我測試的版本裡面 (2012,2014), 除了根據 Partition By 進行分區,還對Order by 不一樣的值產生不一樣的取值。

所以,如果你想看到這個效果,我們不妨把測試樣例數據修改一下,把其中2個DT改成一樣的,如下麵效果

 

;WITH CTE AS(
SELECT 1 AS ID ,'2016-06-05' AS DT,'A' AS UName,135 AS TotalAmount UNION ALL
SELECT 2 AS ID ,'2016-06-05' AS DT,'A' AS UName,148 AS TotalAmount UNION ALL
SELECT 3 AS ID ,'2016-06-02' AS DT,'B' AS UName,120 AS TotalAmount UNION ALL
SELECT 4 AS ID ,'2016-06-02' AS DT,'B' AS UName,153 AS TotalAmount UNION ALL
SELECT 5 AS ID ,'2016-06-10' AS DT,'B' AS UName,198 AS TotalAmount 
)
SELECT * ,
        LAST_VALUE(CTE.TotalAmount) OVER ( PARTITION BY CTE.UName ORDER BY CTE.DT) AS LR
    FROM CTE



ID          DT         UName TotalAmount LR
----------- ---------- ----- ----------- -----------
1           2016-06-01 A     135         135
2           2016-06-05 A     148         148
3           2016-06-02 B     120         120
4           2016-06-06 B     153         153
5           2016-06-10 B     198         198

 

so 現在就看到取值是不一樣的,燃鵝,確還是有一個問題,到底哪個才是Last_Value 呢??查詢計劃說了算~(這個我還真沒驗證過,請各位大神指導一下)

所以啊,不要看名字就覺得First_Value 和 Last_Value 是親兄弟啊!!是隔壁老王的啊!!

好,本次分享到這裡~

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 你好, 世界 <!--EndFragment--> <!--EndFragment--> <!--EndFragment--> <!--EndFragment--> <!--EndFragment--> <!--EndFragment--> <!--EndFragment--> 【寫在開頭:】 『關 ...
  • 文件系統的文件太多,而且是照搬的MINIX的文件系統,不想繼續分析下去了。緩衝區機制和文件系統密切相關,所以這裡就簡單分析一下緩衝區機制。 buffer.c 程式用於對高速緩衝區(池)進行操作和管理。高速緩衝區位於內核代碼塊和主記憶體區之間,見圖9-9 中所示。高速緩衝區在塊設備與內核其它程式之間起著 ...
  • 1、跳轉到一個新的Actitity 新建項目, 新建一個java類OtherScreenActivity 繼承自 Activity類 顯然需要新建一個名為activity_two的android.xml,隨便寫一些控制項佈局一下 MainActivity.java中的代碼如下 當然,click中的代碼 ...
  • 自定義TabBarController Push下一級Controller時 會報這樣的錯誤:Unbalanced calls to begin/end appearance transitions for <XXXViewController: 0x7fcea3730650>. 網上的一些回答,都 ...
  • iOS 直播 實現後臺錄音並推流 從一個月前開始開始接收公司的直播類app.到今天為止測試都已接近尾聲,但是產品哥哥加了一個要求,就是在app進入後臺後也實時保證錄音並且推流. 剛聽到這個的時候我也是懵逼的,可是冷靜下來找資料,還是有所收穫的,在此分享一下. 對於我們的app要求後臺也實時錄音並推流 ...
  • iOS 怎麼設置 UITabBarController 的第n個item為第一響應者? UITabBarController 裡面有個屬性:selectedIndex @property(nonatomic) NSUInteger selectedIndex; UITabBarController ...
  • select count(1) as nums, sd.name from [Master].[dbo].[SYSPROCESSES] spinner join [Master].[dbo].[SYSDATABASES] sd on sp.dbid=sd.dbid--where --sd.name ...
  • 問題 我們經常遇到一種情況,在SSMS中運行很慢的一個查詢,當把查詢轉化成從源到目的資料庫的SSIS數據流以後,需要花費幾倍的時間!源和數據源都沒有任何軟硬體瓶頸,並且沒有大量的格式轉換。之前看了很多關於這種情況的優化方案,例如擴大緩存大小等。雖然也能快一點,但是仍然遠遠比直接在SSMS中查詢的速度 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...