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
  • 移動開發(一):使用.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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...