MariaDB CUME_DIST() 函数的基础用法与实例

MariaDB CUME_DIST() 函数是一个窗口函数,它用于计算当前行在分区中的累积分布。

发布于

MariaDB 是一个开源的关系型数据库管理系统,它是 MySQL 的一个分支。MariaDB 提供了许多 SQL 函数,用于对数据进行各种操作和计算。本文将介绍其中一个函数:CUME_DIST()。MariaDB CUME_DIST() 函数是一个窗口函数,它用于计算当前行在分区中的累积分布。换句话说,它返回当前行的排名占分区总行数的比例。

语法

MariaDB CUME_DIST() 的语法如下:

CUME_DIST() OVER (
  [PARTITION BY partition_expression, ...]
  [ORDER BY sort_expression [ASC | DESC], ...]
)

其中:

  • PARTITION BY 子句用于将数据分成不同的分区,每个分区内的数据都是独立计算的。如果省略该子句,则整个结果集被视为一个分区。
  • ORDER BY 子句用于指定分区内数据的排序方式,影响当前行的排名。如果省略该子句,则分区内数据的顺序是未定义的,因此 CUME_DIST() 函数的结果也是未定义的。
  • ASCDESC 关键字用于指定排序的方向,分别表示升序和降序。如果省略,则默认为升序。

CUME_DIST() 函数的返回值是一个介于 0 和 1 之间的小数,表示当前行的累积分布。如果分区内只有一行数据,则返回值为 1。如果分区内有多行数据,则返回值等于当前行的排名除以分区内的总行数。注意,当前行的排名是按照 ORDER BY 子句中的排序方式确定的,而且如果有相同值的行,则它们的排名是相同的,且都等于最高的排名。例如,如果分区内有 5 行数据,其中有 3 行的值相同,则它们的排名都是 3,而不是 1,2,3。

实例

下面是一些使用 CUME_DIST() 函数的实例,以及相应的代码和输出结果。我们使用的示例数据表是 employees,它包含了员工的编号,姓名,部门,薪水等信息。表结构和部分数据如下:

CREATE TABLE employees (
  id INT PRIMARY KEY,
  name VARCHAR(50),
  department VARCHAR(50),
  salary DECIMAL(10,2)
);

INSERT INTO employees VALUES
(1, 'Alice', 'Sales', 5000.00),
(2, 'Bob', 'Marketing', 6000.00),
(3, 'Charlie', 'IT', 7000.00),
(4, 'David', 'Sales', 8000.00),
(5, 'Eve', 'Marketing', 9000.00),
(6, 'Frank', 'IT', 10000.00),
(7, 'Grace', 'Sales', 11000.00),
(8, 'Helen', 'Marketing', 12000.00),
(9, 'Ivan', 'IT', 13000.00),
(10, 'Jack', 'Sales', 14000.00);

计算全表的累积分布

我们可以使用 CUME_DIST() 函数,不指定 PARTITION BY 子句,来计算全表的累积分布。例如,我们可以按照薪水的升序来计算每个员工的累积分布,代码如下:

SELECT id, name, department, salary,
CUME_DIST() OVER (ORDER BY salary ASC) AS cume_dist
FROM employees;

输出结果如下:

+----+-------+------------+----------+-----------+
| id | name  | department | salary   | cume_dist |
+----+-------+------------+----------+-----------+
|  1 | Alice | Sales      |  5000.00 |      0.10 |
|  2 | Bob   | Marketing  |  6000.00 |      0.20 |
|  3 | Charlie | IT       |  7000.00 |      0.30 |
|  4 | David | Sales      |  8000.00 |      0.40 |
|  5 | Eve   | Marketing  |  9000.00 |      0.50 |
|  6 | Frank | IT         | 10000.00 |      0.60 |
|  7 | Grace | Sales      | 11000.00 |      0.70 |
|  8 | Helen | Marketing  | 12000.00 |      0.80 |
|  9 | Ivan  | IT         | 13000.00 |      0.90 |
| 10 | Jack  | Sales      | 14000.00 |      1.00 |
+----+-------+------------+----------+-----------+

从输出结果可以看出,CUME_DIST() 函数返回了每个员工的薪水在全表中的累积分布。例如,Alice 的薪水是 5000.00,是全表中最低的,因此她的累积分布是 0.10,表示她的排名占全表总行数(10)的 10%。而 Jack 的薪水是 14000.00,是全表中最高的,因此他的累积分布是 1.00,表示他的排名占全表总行数(10)的 100%。

计算分区的累积分布

我们也可以使用 CUME_DIST() 函数,指定 PARTITION BY 子句,来计算分区的累积分布。例如,我们可以按照部门来分区数据,然后按照薪水的升序来计算每个员工在各自部门中的累积分布,代码如下:

SELECT id, name, department, salary,
CUME_DIST() OVER (PARTITION BY department ORDER BY salary ASC) AS cume_dist
FROM employees;

输出结果如下:

+----+-------+------------+----------+-----------+
| id | name  | department | salary   | cume_dist |
+----+-------+------------+----------+-----------+
|  3 | Charlie | IT       |  7000.00 |      0.25 |
|  6 | Frank | IT         | 10000.00 |      0.50 |
|  9 | Ivan  | IT         | 13000.00 |      0.75 |
|  1 | Alice | Sales      |  5000.00 |      0.25 |
|  4 | David | Sales      |  8000.00 |      0.50 |
|  7 | Grace | Sales      | 11000.00 |      0.75 |
| 10 | Jack  | Sales      | 14000.00 |      1.00 |
|  2 | Bob   | Marketing  |  6000.00 |      0.33 |
|  5 | Eve   | Marketing  |  9000.00 |      0.67 |
|  8 | Helen | Marketing  | 12000.00 |      1.00 |
+----+-------+------------+----------+-----------+

从输出结果可以看出,CUME_DIST() 函数返回了每个员工的薪水在各自部门中的累积分布。例如,Charlie 的薪水是 7000.00,是 IT 部门中最低的,因此他的累积分布是 0.25,表示他的排名占 IT 部门总行数(4)的 25%。而 Helen 的薪水是 12000.00,是 Marketing 部门中最高的。

计算累积分布的百分比

我们可以使用 CUME_DIST() 函数,结合 ROUND() 函数,来计算累积分布的百分比。例如,我们可以按照部门来分区数据,然后按照薪水的升序来计算每个员工在各自部门中的累积分布的百分比,保留两位小数,代码如下:

SELECT id, name, department, salary,
ROUND(CUME_DIST() OVER (PARTITION BY department ORDER BY salary ASC) * 100, 2) AS cume_dist_pct
FROM employees;

输出结果如下:

+----+---------+------------+----------+---------------+
| id | name    | department | salary   | cume_dist_pct |
+----+---------+------------+----------+---------------+
|  3 | Charlie | IT         |  7000.00 |         25.00 |
|  6 | Frank   | IT         | 10000.00 |         50.00 |
|  9 | Ivan    | IT         | 13000.00 |         75.00 |
|  1 | Alice   | Sales      |  5000.00 |         25.00 |
|  4 | David   | Sales      |  8000.00 |         50.00 |
|  7 | Grace   | Sales      | 11000.00 |         75.00 |
| 10 | Jack    | Sales      | 14000.00 |        100.00 |
|  2 | Bob     | Marketing  |  6000.00 |         33.33 |
|  5 | Eve     | Marketing  |  9000.00 |         66.67 |
|  8 | Helen   | Marketing  | 12000.00 |        100.00 |
+----+---------+------------+----------+---------------+

从输出结果可以看出,CUME_DIST() 函数返回了每个员工的薪水在各自部门中的累积分布的百分比。例如,Charlie 的薪水是 7000.00,是 IT 部门中最低的,因此他的累积分布的百分比是 25.00%,表示他的排名占 IT 部门总行数(4)的 25%。而 Helen 的薪水是 12000.00,是 Marketing 部门中最高的,因此她的累积分布的百分比是 100.00%,表示她的排名占 Marketing 部门总行数(3)的 100%。

计算累积分布的排名

我们也可以使用 CUME_DIST() 函数,结合 COUNT() 函数,来计算累积分布的排名。例如,我们可以按照部门来分区数据,然后按照薪水的升序来计算每个员工在各自部门中的累积分布的排名,代码如下:

SELECT id, name, department, salary,
CUME_DIST() OVER (PARTITION BY department ORDER BY salary ASC) * COUNT(*) OVER (PARTITION BY department) AS cume_dist_rank
FROM employees;

输出结果如下:

+----+---------+------------+----------+----------------+
| id | name    | department | salary   | cume_dist_rank |
+----+---------+------------+----------+----------------+
|  3 | Charlie | IT         |  7000.00 |              1 |
|  6 | Frank   | IT         | 10000.00 |              2 |
|  9 | Ivan    | IT         | 13000.00 |              3 |
|  1 | Alice   | Sales      |  5000.00 |              1 |
|  4 | David   | Sales      |  8000.00 |              2 |
|  7 | Grace   | Sales      | 11000.00 |              3 |
| 10 | Jack    | Sales      | 14000.00 |              4 |
|  2 | Bob     | Marketing  |  6000.00 |              1 |
|  5 | Eve     | Marketing  |  9000.00 |              2 |
|  8 | Helen   | Marketing  | 12000.00 |              3 |
+----+---------+------------+----------+----------------+

从输出结果可以看出,CUME_DIST() 函数返回了每个员工的薪水在各自部门中的累积分布的排名。例如,Charlie 的薪水是 7000.00,是 IT 部门中最低的,因此他的累积分布的排名是 1,表示他是 IT 部门中排名第一的员工。而 Helen 的薪水是 12000.00,是 Marketing 部门中最高的,因此她的累积分布的排名是 3,表示她是 Marketing 部门中排名第三的员工。

计算累积分布的反向排序

我们还可以使用 CUME_DIST() 函数,指定 DESC 关键字,来计算累积分布的反向排序。例如,我们可以按照部门来分区数据,然后按照薪水的降序来计算每个员工在各自部门中的累积分布,代码如下:

SELECT id, name, department, salary,
CUME_DIST() OVER (PARTITION BY department ORDER BY salary DESC) AS cume_dist
FROM employees;

输出结果如下:

+----+---------+------------+----------+-----------+
| id | name    | department | salary   | cume_dist |
+----+---------+------------+----------+-----------+
|  9 | Ivan    | IT         | 13000.00 |      0.25 |
|  6 | Frank   | IT         | 10000.00 |      0.50 |
|  3 | Charlie | IT         |  7000.00 |      0.75 |
| 10 | Jack    | Sales      | 14000.00 |      0.25 |
|  7 | Grace   | Sales      | 11000.00 |      0.50 |
|  4 | David   | Sales      |  8000.00 |      0.75 |
|  1 | Alice   | Sales      |  5000.00 |      1.00 |
|  8 | Helen   | Marketing  | 12000.00 |      0.33 |
|  5 | Eve     | Marketing  |  9000.00 |      0.67 |
|  2 | Bob     | Marketing  |  6000.00 |      1.00 |
+----+---------+------------+----------+-----------+

从输出结果可以看出,CUME_DIST() 函数返回了每个员工的薪水在各自部门中的累积分布的反向排序。例如,Ivan 的薪水是 13000.00,是 IT 部门中最高的,因此他的累积分布是 0.25,表示他的排名占 IT 部门总行数(4)的 25%。而 Bob 的薪水是 6000.00,是 Marketing 部门中最低的,因此他的累积分布是 1.00,表示他的排名占 Marketing 部门总行数(3)的 100%。

相关函数

除了 CUME_DIST() 函数,MariaDB 还提供了一些其他的窗口函数,用于计算分区内数据的排名和分布。这里列举了一些常用的函数,并作简单的介绍和举例。

  • RANK() 函数:用于计算当前行在分区内的排名,按照 ORDER BY 子句中的排序方式确定。如果有相同值的行,则它们的排名是相同的,且都等于最高的排名。例如,我们可以按照部门来分区数据,然后按照薪水的升序来计算每个员工在各自部门中的排名,代码如下:

    SELECT id, name, department, salary,
    RANK() OVER (PARTITION BY department ORDER BY salary ASC) AS rank
    FROM employees;
    

    输出结果如下:

    +----+-------+------------+----------+------+
    | id | name  | department | salary   | rank |
    +----+-------+------------+----------+------+
    |  3 | Charlie | IT       |  7000.00 |    1 |
    |  6 | Frank | IT         | 10000.00 |    2 |
    |  9 | Ivan  | IT         | 13000.00 |    3 |
    |  1 | Alice | Sales      |  5000.00 |    1 |
    |  4 | David | Sales      |  8000.00 |    2 |
    |  7 | Grace | Sales      | 11000.00 |    3 |
    | 10 | Jack  | Sales      | 14000.00 |    4 |
    |  2 | Bob   | Marketing  |  6000.00 |    1 |
    |  5 | Eve   | Marketing  |  9000.00 |    2 |
    |  8 | Helen | Marketing  | 12000.00 |    3 |
    +----+-------+------------+----------+------+

    从输出结果可以看出,RANK() 函数返回了每个员工的薪水在各自部门中的排名。例如,Charlie 的薪水是 7000.00,是 IT 部门中最低的,因此他的排名是 1,表示他是 IT 部门中排名第一的员工。而 Jack 的薪水是 14000.00,是 Sales 部门中最高的,因此他的排名是 4,表示他是 Sales 部门中排名第四的员工。

  • DENSE_RANK() 函数:用于计算当前行在分区内的排名,按照 ORDER BY 子句中的排序方式确定。如果有相同值的行,则它们的排名是相同的,但不会跳过任何排名。例如,我们可以按照部门来分区数据,然后按照薪水的升序来计算每个员工在各自部门中的排名,代码如下:

    SELECT id, name, department, salary,
    DENSE_RANK() OVER (PARTITION BY department ORDER BY salary ASC) AS dense_rank
    FROM employees;
    

    输出结果如下:

    +----+-------+------------+----------+------------+
    | id | name  | department | salary   | dense_rank |
    +----+-------+------------+----------+------------+
    |  3 | Charlie | IT       |  7000.00 |          1 |
    |  6 | Frank | IT         | 10000.00 |          2 |
    |  9 | Ivan  | IT         | 13000.00 |          3 |
    |  1 | Alice | Sales      |  5000.00 |          1 |
    |  4 | David | Sales      |  8000.00 |          2 |
    |  7 | Grace | Sales      | 11000.00 |          3 |
    | 10 | Jack  | Sales      | 14000.00 |          4 |
    |  2 | Bob   | Marketing  |  6000.00 |          1 |
    |  5 | Eve   | Marketing  |  9000.00 |          2 |
    |  8 | Helen | Marketing  | 12000.00 |          3 |
    +----+-------+------------+----------+------------+

    从输出结果可以看出,DENSE_RANK() 函数返回了每个员工的薪水在各自部门中的排名。与 RANK() 函数不同的是,DENSE_RANK() 函数不会跳过任何排名,即使有相同值的行。例如,Charlie 的薪水是 7000.00,是 IT 部门中最低的,因此他的排名是 1,表示他是 IT 部门中排名第一的员工。而 Frank 的薪水是 10000.00,是 IT 部门中第二低的,因此他的排名是 2,表示他是 IT 部门中排名第二的员工。注意,与 RANK() 函数不同,DENSE_RANK() 函数不会跳过排名 2,即使有相同值的行。

  • PERCENT_RANK() 函数:用于计算当前行在分区内的百分比排名,按照 ORDER BY 子句中的排序方式确定。如果有相同值的行,则它们的百分比排名是相同的。它的计算公式是 (rank - 1) / (total rows - 1),其中 rank 是当前行的排名,total rows 是分区内的总行数。例如,我们可以按照部门来分区数据,然后按照薪水的升序来计算每个员工在各自部门中的百分比排名,代码如下:

    SELECT id, name, department, salary,
    PERCENT_RANK() OVER (PARTITION BY department ORDER BY salary ASC) AS percent_rank
    FROM employees;
    

    输出结果如下:

    +----+-------+------------+----------+--------------+
    | id | name  | department | salary   | percent_rank |
    +----+-------+------------+----------+--------------+
    |  3 | Charlie | IT       |  7000.00 |         0.00 |
    |  6 | Frank | IT         | 10000.00 |         0.33 |
    |  9 | Ivan  | IT         | 13000.00 |         0.67 |
    |  1 | Alice | Sales      |  5000.00 |         0.00 |
    |  4 | David | Sales      |  8000.00 |         0.33 |
    |  7 | Grace | Sales      | 11000.00 |         0.67 |
    | 10 | Jack  | Sales      | 14000.00 |         1.00 |
    |  2 | Bob   | Marketing  |  6000.00 |         0.00 |
    |  5 | Eve   | Marketing  |  9000.00 |         0.50 |
    |  8 | Helen | Marketing  | 12000.00 |         1.00 |
    +----+-------+------------+----------+--------------+

    从输出结果可以看出,PERCENT_RANK() 函数返回了每个员工的薪水在各自部门中的百分比排名。例如,Charlie 的薪水是 7000.00,是 IT 部门中最低的,因此他的百分比排名是 0.00,表示他是 IT 部门中排名最低的员工。而 Jack 的薪水是 14000.00,是 Sales 部门中最高的,因此他的百分比排名是 1.00,表示他是 Sales 部门中排名最高的员工。

结论

本文介绍了 MariaDB 的 CUME_DIST() 函数,它是一个窗口函数,用于计算当前行在分区中的累积分布。我们通过一些实例,展示了如何使用该函数,以及它的输出结果。我们还介绍了一些与该函数相关的其他窗口函数,用于计算分区内数据的排名和分布。