1. 程式人生 > 其它 >mysql開窗函式

mysql開窗函式

開窗函式

注:開窗函式只有MySQL8.0版本之後才有

1. 開窗函式

  • 官網定義:A window function performs an aggregate-like operation on a set of query rows. However, whereas an aggregate operation groups query rows into a single result row, a window function produces a result for each query row。
  • 開窗函式和像聚合函式一樣,查詢多行資料,然而,聚合操作將查詢行分組到單個結果行中,而視窗函式則為每個查詢行生成一個結果。
    • 對其進行函式求值的行稱為當前行。
    • 與進行函式計算的當前行相關的查詢行構成當前行的視窗。

MySQL提供的開窗函式

  • DENSE_RNAK() :其分割槽中當前行的排名,無間隙
  • FIRST_VALUE():視窗中第一行中的引數值
  • LAG():分割槽中滯後當前行的行的引數值
  • LAST_VALUE():視窗中最後一行中的引數值
  • LEAD():分割槽中領先當前行的引數值
  • NTILE():其分割槽中當前行的儲存桶編號。
  • RANK():當前行在其分割槽內的排名,帶有間隙
  • ROW_NUMBER():當前行在其分割槽內的排名,帶有間隙
mysql> SELECT
         time, subject, val,
         FIRST_VALUE(val)  OVER w AS 'first',
         LAST_VALUE(val)   OVER w AS 'last',
         NTH_VALUE(val, 2) OVER w AS 'second',
         NTH_VALUE(val, 4) OVER w AS 'fourth'
       FROM observations
       WINDOW w AS (PARTITION BY subject ORDER BY time
                    ROWS UNBOUNDED PRECEDING);
+----------+---------+------+-------+------+--------+--------+
| time     | subject | val  | first | last | second | fourth |
+----------+---------+------+-------+------+--------+--------+
| 07:00:00 | st113   |   10 |    10 |   10 |   NULL |   NULL |
| 07:15:00 | st113   |    9 |    10 |    9 |      9 |   NULL |
| 07:30:00 | st113   |   25 |    10 |   25 |      9 |   NULL |
| 07:45:00 | st113   |   20 |    10 |   20 |      9 |     20 |
| 07:00:00 | xh458   |    0 |     0 |    0 |   NULL |   NULL |
| 07:15:00 | xh458   |   10 |     0 |   10 |     10 |   NULL |
| 07:30:00 | xh458   |    5 |     0 |    5 |     10 |   NULL |
| 07:45:00 | xh458   |   30 |     0 |   30 |     10 |     30 |
| 08:00:00 | xh458   |   25 |     0 |   25 |     10 |     30 |
+----------+---------+------+-------+------+--------+--------+

mysql> SELECT
         t, val,
         LAG(val)        OVER w AS 'lag',
         LEAD(val)       OVER w AS 'lead',
         val - LAG(val)  OVER w AS 'lag diff',
         val - LEAD(val) OVER w AS 'lead diff'
       FROM series
       WINDOW w AS (ORDER BY t);
+----------+------+------+------+----------+-----------+
| t        | val  | lag  | lead | lag diff | lead diff |
+----------+------+------+------+----------+-----------+
| 12:00:00 |  100 | NULL |  125 |     NULL |       -25 |
| 13:00:00 |  125 |  100 |  132 |       25 |        -7 |
| 14:00:00 |  132 |  125 |  145 |        7 |       -13 |
| 15:00:00 |  145 |  132 |  140 |       13 |         5 |
| 16:00:00 |  140 |  145 |  150 |       -5 |       -10 |
| 17:00:00 |  150 |  140 |  200 |       10 |       -50 |
| 18:00:00 |  200 |  150 | NULL |       50 |      NULL |
+----------+------+------+------+----------+-----------+

mysql> SELECT
         val,
         ROW_NUMBER() OVER w AS 'row_number',
         NTILE(2)     OVER w AS 'ntile2',
         NTILE(4)     OVER w AS 'ntile4'
       FROM numbers
       WINDOW w AS (ORDER BY val);
+------+------------+--------+--------+
| val  | row_number | ntile2 | ntile4 |
+------+------------+--------+--------+
|    1 |          1 |      1 |      1 |
|    1 |          2 |      1 |      1 |
|    2 |          3 |      1 |      1 |
|    3 |          4 |      1 |      2 |
|    3 |          5 |      1 |      2 |
|    3 |          6 |      2 |      3 |
|    4 |          7 |      2 |      3 |
|    4 |          8 |      2 |      4 |
|    5 |          9 |      2 |      4 |
+------+------------+--------+--------+

1.1 開窗函式和聚合函式的區別

  • 資料
  • 使用聚合函式的效果
SELECT 
	country, 
	SUM(profit) AS country_profit
FROM sales
GROUP BY country
ORDER BY country;
  • 使用開窗函式的效果
SELECT
	year, country, product, profit,
	SUM(profit) OVER() AS total_profit,
	SUM(profit) OVER(PARTITION BY country) AS country_profit
FROM sales
ORDER BY country, year, product, profit;

第一個 OVER 子句為空,它將整個查詢行集視為單個分割槽。因此,視窗函式生成全域性和,但對每行都這樣做。

第二個 OVER 子句按country對行進行分割槽,從而生成country分割槽的總和。該函式為每個分割槽行生成此總和。

1.2 要使用開窗函式(或將聚合函式視為開窗函式),請在函式呼叫後包含一個 OVER 子句。OVER 子句有兩種形式:

  • over_clause:
    {OVER (window_spec) | OVER window_name}

    這兩種形式都定義了視窗函式應如何處理查詢行。它們的不同之處在於,視窗是直接在 OVER 子句中定義,還是由對查詢中其他位置定義的命名視窗的引用提供:

    • 在第一種情況下,視窗規範直接出現在 OVER 子句中,位於括號之間。
    • 在第二種情況下,window_name是由查詢中其他位置的 WINDOW 子句定義的視窗規範的名稱。
-- 第一種情況
SELECT
         year, country, product, profit,
         ROW_NUMBER() OVER(PARTITION BY country) AS row_num1,
         ROW_NUMBER() OVER(PARTITION BY country ORDER BY year, product) AS row_num2
FROM sales;

-- 第二種情況
SELECT
         val,
         ROW_NUMBER()   OVER w AS 'row_number',
         CUME_DIST()    OVER w AS 'cume_dist',
         PERCENT_RANK() OVER w AS 'percent_rank'
FROM numbers
WINDOW w AS (ORDER BY val);
  • OVER (window_spec)語法

    • window_name:視窗函式名稱

      • 視窗函式命名規則
    • partition_clause:子句指示如何將查詢行劃分為多個組。給定行的視窗函式結果基於包含該行的分割槽的行。如果省略了partition BY,則存在一個由所有查詢行組成的分割槽。

    • order_clause:如果省略 ORDER BY,則分割槽行是無序的,不隱含處理順序,並且所有分割槽行都是相同的。

1.3 開窗函式的執行順序

開窗函式只允許在select和 ORDER BY 子句中使用。查詢結果行 由 FROM 子句、在 WHERE、GROUP BY 和 HAVING 處理之後確定,並且視窗執行發生在 ORDER BY、LIMIT 和 SELECT DISTINCT 之前。

總結就是: 開窗函式在WHERE,GROUP BY 和 HAVING之後執行,在在 ORDER BY、LIMIT 和 SELECT DISTINCT 之前執行.

2. 聚合函式

聚合函式經常和開窗函式一起使用。

參考連結