PostgreSQL 的視窗函數 OVER, WINDOW, PARTITION BY, RANGE

来源:https://www.cnblogs.com/milton/archive/2022/05/27/16315790.html
-Advertisement-
Play Games

最近在數據處理中用到了窗函數, 把使用方法記錄一下, 暫時只有分組排序和滑動時間視窗的例子, 以後再逐步添加. 在SQL查詢時, 會遇到有兩類需要分組統計的場景, 在之前的SQL語法中是不方便實現的. 使用窗函數直接SQL中使用窗函數就能解決這些問題, 否則需要使用臨時表, 函數或存儲過程進行處理.... ...


最近在數據處理中用到了窗函數, 把使用方法記錄一下, 暫時只有分組排序和滑動時間視窗的例子, 以後再逐步添加

場景

在SQL查詢時, 會遇到有兩類需要分組統計的場景, 在之前的SQL語法中是不方便實現的

  1. 場景1: 顧客維修設備的記錄表, 每次維修產生一條記錄, 每個記錄包含時間, 顧客ID和維修金額, 要取出每個顧客的維修次數和最後一次維修時的金額
  2. 場景2: 還是上面的維修記錄表, 要取出每個顧客的每次維修之間的時間間隔
  3. 場景3: 一個用戶賬戶的交易流水錶, 要求每個小時的交易筆數和平均收支金額, 這個平均數的統計範圍是兩個小時(整點時間的前後一個小時)

使用窗函數直接SQL中使用窗函數就能解決這些問題, 否則需要使用臨時表, 函數或存儲過程進行處理.

窗函數

PostgreSQL 從2010年的版本8開始就支持窗函數了.

文檔

詳細說明建議查看官方文檔 https://www.postgresql.org/docs/current/tutorial-window.html

函數說明

窗函數(window function)的計算方式與傳統的單行和聚合不同

  1. 窗函數是在當前表中, 基於當前行的相關行的計算, 註意是基於多行的計算
  2. 屬於一種聚合計算, 可以使用聚合類型的函數(aggregate function)
  3. 使用窗函數並不會導致結果的聚合, 也就是結果依然是當前的行結構

所以綜合的說, 視窗函數就是在行的基礎上, 允許對多行數據進行計算. 下麵是一個簡單的窗函數例子, 將每個員工的薪資與其所在的部門的平均薪資進行比較

SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary;

關鍵詞

使用窗函數時會用到的一些關鍵詞

  • OVER 前面的查詢基於後面的視窗
  • PARTITION BY 類似於 GROUP BY 的語義, 專用於視窗的分組
  • ORDER BY 窗內的排序依據, 依據的欄位決定了 RANGE 的類型
  • RANGE ... PRECEDING 在當前值之前的範圍, 基準是當前記錄這個 ORDER BY 欄位的值
  • RANGE ... FOLLOWING 在當前值之後的範圍, 基準是當前記錄這個 ORDER BY 欄位的值
  • RANGE BETWEEN ... PRECEDING AND ... FOLLOWING 前後範圍的組合
  • WINDOW 將視窗命名為變數, 可以在 SELECT 中重覆使用

示例

按視窗打序號

功能: 將數據按指定的欄位分組, 再按另一個欄位排列, 給每個分組裡的數據打上序號.

這是一個常用技巧, 例如要計算各組內記錄之間的時間間隔, 但是用時間不方便join, 打完序號後就可以用序號join了

SELECT
    ROW_NUMBER() OVER w1 AS rn,
    sample_01.*
FROM
    sample_01
WINDOW 
w1 AS (PARTITION BY field_name ORDER BY created_at ASC);

簡單時間視窗統計

功能: 將數據表按指定欄位(日期類型)進行排序, 然後基於每個記錄的這個欄位創建一個固定寬度的時間視窗, 對視窗內的多個記錄進行統計

統計單個欄位, 可以直接寫在select中

SELECT
    MAX(amount) OVER (ORDER BY traded_at RANGE '30 minutes' PRECEDING) AS amount_max,
    *
FROM sample_01
WHERE card_num = '6210812500006111111'

基於時間視窗變數進行多欄位統計

功能: 和前一個功能一樣, 但是要進行多個不同的統計, 要重覆用到這個視窗函數

如果要統計多個欄位, 可以抽出單獨的WINDOW

SELECT
    MAX(rn) OVER w1 AS rn_max,
    MAX(amount) OVER w1 AS amount_max,
    AVG(amount) OVER w1 AS amount_avg,
    *
FROM sample_01_diff
WINDOW
    -- w1 AS (ORDER BY traded_at RANGE '30 minutes' PRECEDING)
    w1 AS (PARTITION BY card_num ORDER BY traded_at RANGE BETWEEN '30 minutes' PRECEDING AND '30 minutes' FOLLOWING)
ORDER BY
    rn ASC

在這個例子中

  1. 先依據 card_num 這個欄位進行分區,
  2. 然後按 traded_at 這個欄位進行排序,
  3. 對每個記錄的 traded_at 值, 開啟一個 RANGE, 包含前面的30分鐘和後面的30分鐘, RANGE 中能用的類型和 ORDER BY 的欄位類型是相關的
  4. SELECT中的 MAX, MIN 等聚合函數, 是基於上面的 RANGE 進行的

In RANGE mode, these options require that the ORDER BY clause specify exactly one column. The offset specifies the maximum difference between the value of that column in the current row and its value in preceding or following rows of the frame. The data type of the offset expression varies depending on the data type of the ordering column. For numeric ordering columns it is typically of the same type as the ordering column, but for datetime ordering columns it is an interval. For example, if the ordering column is of type date or timestamp, one could write RANGE BETWEEN '1 day' PRECEDING AND '10 days' FOLLOWING. The offset is still required to be non-null and non-negative, though the meaning of “non-negative” depends on its data type.

多個視窗多個欄位同時統計

功能: 在前面的功能基礎上, 同時存在多個時間視窗

SELECT
    -- 1 hour
    SUM(amount_in) OVER w1h AS h1_amount_in_sum,
    SUM(
        CASE
            WHEN amount_in = 0 THEN 0
            ELSE 1
        END
    ) OVER w1h AS h1_amount_in_count,
    SUM(amount_out) OVER w1h AS h1_amount_out_sum,
    SUM(
        CASE
            WHEN amount_out = 0 THEN 0
            ELSE 1
        END
    ) OVER w1h AS h1_amount_out_count,
    SUM(amount) OVER w1h AS h1_amount_sum,
    COUNT(amount) OVER w1h AS h1_amount_count,
    ROUND(AVG(amount) OVER w1h, 2) AS h1_amount_avg,
    FIRST_VALUE(amount) OVER w1h AS h1_amount_first,
    LAST_VALUE(amount) OVER w1h AS h1_amount_last,
    MAX(amount) OVER w1h AS h1_amount_max,
    MIN(amount) OVER w1h AS h1_amount_min,
    -- 3 hour
    SUM(amount_in) OVER w3h AS h3_amount_in_sum,
    SUM(
        CASE
            WHEN amount_in = 0 THEN 0
            ELSE 1
        END
    ) OVER w3h AS h3_amount_in_count,
    SUM(amount_out) OVER w3h AS h3_amount_out_sum,
    SUM(
        CASE
            WHEN amount_out = 0 THEN 0
            ELSE 1
        END
    ) OVER w3h AS h3_amount_out_count,
    SUM(amount) OVER w3h AS h3_amount_sum,
    COUNT(amount) OVER w3h AS h3_amount_count,
    ROUND(AVG(amount) OVER w3h, 2) AS h3_amount_avg,
    FIRST_VALUE(amount) OVER w3h AS h3_amount_first,
    LAST_VALUE(amount) OVER w3h AS h3_amount_last,
    MAX(amount) OVER w3h AS h3_amount_max,
    MIN(amount) OVER w3h AS h3_amount_min,
    *
FROM sample_01
WINDOW
    w1h AS (PARTITION BY card_num ORDER BY traded_at RANGE BETWEEN '30 minutes' PRECEDING AND '30 minutes' FOLLOWING),
    w3h AS (PARTITION BY card_num ORDER BY traded_at RANGE BETWEEN '90 minutes' PRECEDING AND '90 minutes' FOLLOWING)
;

參考


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

-Advertisement-
Play Games
更多相關文章
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 本文介紹了在jenkins中maven的安裝及配置(安裝maven及jdk的方法),以及如何在jenkins中創建maven任務。 有三點需要註意的地方。 maven一定要安裝在jenkins伺服器上。 maven安裝之前要先安裝jdk。 建任務 ...
  • curl curl是一個非常實用的、用來與伺服器之間傳輸數據的工具;支持的協議包括 (DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, S ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 1. 查看自己的網關地址 點擊虛擬機中編輯按鈕,選中虛擬網路編輯器 2.選擇點擊VMnet8,再點擊NAT設置 3.記住此時頁面的網關IP 4.進入虛擬機終端操作界面,切換到管理員用戶 5.找到CentOS8網路配置文件 cd /etc/sysc ...
  • 本文例子參考《STM32單片機開發實例——基於Proteus虛擬模擬與HAL/LL庫》 源代碼:https://github.com/LanLinnet/STM33F103R6 項目要求 掌握$I^2C$的通訊方法和時序,通過串口發送數據,單片機接收並存入AT24C02首地址中。按下按鍵BTN,單片 ...
  • 思路: 1、socket 建立一個數據報套接字。 2、定義一個struct ifreq ifr 結構體。將網路名稱如“eth0” 賦值給ifr結構體的ifr.ifr_name。 3、調用ioctl(sockfd, SIOCGIFFLAGS, &ifr) 獲取網路標識。 如需設置網路標識,更改ifr結 ...
  • teacher表: iddeptnamephonemobile 101 1 Shrivell 2753 07986 555 1234 102 1 Throd 2754 07122 555 1920 103 1 Splint 2293 104 Spiregrain 3287 105 2 Cutflow ...
  • 本文介紹如何使用 SELECT 語句查詢 SQL 如何對錶進行創建、更新和刪除操作 中創建的 Product 表中數據。這裡使用的 SELECT 語句是 SQL 最基本也是最重要的語句。 請大家在實際運行本文中的 SELECT 語句時,親身體驗一下其書寫方法和執行結果。 執行查詢操作時可以指定想要查 ...
  • 1 Hadoop介紹 Hadoop是Apache旗下的一個用java語言實現開源軟體框架,是一個開發和運行處理大規模數據的軟體平臺。允許使用簡單的編程模型在大量電腦集群上對大型數據集進行分散式處理。狹義上說,Hadoop指Apache這款開源框架,它的核心組件有: HDFS(分散式文件系統):解決 ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...