天天看點

mysql視窗函數over中rows_MySQL視窗函數

作者:楓林晚粥

下面的講解将基于這個employee2表:

mysql> SELECT * FROM employee2;
+----+-----------+------+---------+---------+
| id | name      | age  | salary  | dept_id |
+----+-----------+------+---------+---------+
|  3 | 小肖      |   29 | 30000.0 |       1 |
|  4 | 小東      |   30 | 40000.0 |       2 |
|  6 | 小非      |   24 | 23456.0 |       3 |
|  7 | 曉飛      |   30 | 15000.0 |       4 |
|  8 | 小林      |   23 | 24000.0 |    NULL |
| 10 | 小五      |   20 |  4500.0 |    NULL |
| 11 | 張山      |   24 | 40000.0 |       1 |
| 12 | 小肖      |   28 | 35000.0 |       2 |
| 13 | 李四      |   23 | 50000.0 |       1 |
| 17 | 王武      |   24 | 56000.0 |       2 |
| 18 | 豬小屁    |    2 | 56000.0 |       2 |
| 19 | 小玉      |   25 | 58000.0 |       1 |
| 21 | 小張      |   23 | 50000.0 |       1 |
| 22 | 小胡      |   25 | 25000.0 |       2 |
| 96 | 小肖      |   19 | 35000.0 |       1 |
| 97 | 小林      |   20 | 20000.0 |       2 |
+----+-----------+------+---------+---------+
16 rows in set (0.00 sec)

           

視窗函數是OVER(),其中對應子句有PARTITION BY 以及 ORDER BY子句,是以形式有:

  • OVER():這時候,是一個空子句,此時的效果和沒有使用OVER()函數是一樣的,作用的是這個表所有資料構成的視窗。
mysql> SELECT
-> name,
-> salary,
-> MAX(salary) OVER() AS max_salary -- 作用于一整個視窗,此時傳回的是所有資料中的MAX(salary),表示所有員工的最大工資
-> FROM employee2;
+-----------+---------+------------+
| name      | salary  | max_salary |
+-----------+---------+------------+
| 小肖      | 30000.0 |    58000.0 |
| 小東      | 40000.0 |    58000.0 |
| 小非      | 23456.0 |    58000.0 |
| 曉飛      | 15000.0 |    58000.0 |
| 小林      | 24000.0 |    58000.0 |
| 小五      |  4500.0 |    58000.0 |
| 張山      | 40000.0 |    58000.0 |
| 小肖      | 35000.0 |    58000.0 |
| 李四      | 50000.0 |    58000.0 |
| 王武      | 56000.0 |    58000.0 |
| 豬小屁    | 56000.0 |    58000.0 |
| 小玉      | 58000.0 |    58000.0 |
| 小張      | 50000.0 |    58000.0 |
| 小胡      | 25000.0 |    58000.0 |
| 小肖      | 35000.0 |    58000.0 |
| 小林      | 20000.0 |    58000.0 |
+-----------+---------+------------+
16 rows in set (0.00 sec)

mysql> SELECT
-> name,
-> salary,
-> MAX(salary) OVER() -- 擷取部門為1的所有員工的name,salary以及這個部門的最大工資
-> FROM employee2
-> WHERE dept_id = 1;
+--------+---------+--------------------+
| name   | salary  | MAX(salary) OVER() |
+--------+---------+--------------------+
| 小肖   | 30000.0 |            58000.0 |
| 張山   | 40000.0 |            58000.0 |
| 李四   | 50000.0 |            58000.0 |
| 小玉   | 58000.0 |            58000.0 |
| 小張   | 50000.0 |            58000.0 |
| 小肖   | 35000.0 |            58000.0 |
+--------+---------+--------------------+
6 rows in set (0.00 sec)

           
  • OVER(PARTITION BY yyy1,yyy2,yyy3):含有了PARTITION BY 子句,此時就會根據yyy1,yyy2,yyy3這些列構成的整體進行劃分視窗,隻有這些列構成的整體相同,才會處在同一個視窗中。
mysql> SELECT
-> name,
-> salary,
-> MAX(salary) OVER(PARTITION BY dept_id) AS dept_max_salary -- 利用了PARTITION BY ,進而根據dept_id進行分組,然後擷取每個分組的最大值
-> FROM employee2;
+-----------+---------+-----------------+
| name      | salary  | dept_max_salary |
+-----------+---------+-----------------+
| 小林      | 24000.0 |         24000.0 | --| 分組為NULL的
| 小五      |  4500.0 |         24000.0 | --|
| 小肖      | 30000.0 |         58000.0 | -----|
| 張山      | 40000.0 |         58000.0 |
| 李四      | 50000.0 |         58000.0 |     -- 分組為dept_id = 1的
| 小玉      | 58000.0 |         58000.0 |
| 小張      | 50000.0 |         58000.0 |
| 小肖      | 35000.0 |         58000.0 | -----|
| 小東      | 40000.0 |         56000.0 | ---------|
| 小肖      | 35000.0 |         56000.0 |
| 王武      | 56000.0 |         56000.0 |
| 豬小屁    | 56000.0 |         56000.0 |      -- 分組為dept_id = 2的
| 小胡      | 25000.0 |         56000.0 |
| 小林      | 20000.0 |         56000.0 | ---------|
| 小非      | 23456.0 |         23456.0 | -- ------------| 分組為dept_id = 3的
| 曉飛      | 15000.0 |         15000.0 | -- --------------| 分組為dept_id = 4的
+-----------+---------+-----------------+
16 rows in set (0.00 sec)

           
  • OVER(ORDER BY yyy1,yyy2,yyy3 ASC\DESC):每個視窗中利用ORDER BY子句,這時候将按照yyy1進行對應的升序\降序的順序進行排序,如果yyy1相同,将根據yyy2排序(和ORDER BY 的用法一樣),這時候不僅會進行排序操作,如果是SUM與其連用的話,同時進行了累加的操作,即值是目前行加上前一行對應的值。但是下面的例子中卻發現ORDER BY 後面對應的值相同的時候,并不是目前這一行加上以前行的值,例如ORDER BY salary\ORDER BY name的時候。
mysql> SELECT
-> name,
-> salary,
-> SUM(salary) OVER(ORDER BY salary) AS already_paid_salary -- 利用ORDER BY ,視窗中對應的行将按照salary進行升序排序,然後調用SUM聚集 函數,不同的視窗進行累計
-> FROM employee2;
+-----------+---------+---------------------+
| name      | salary  | already_paid_salary |
+-----------+---------+---------------------+
| 小五      |  4500.0 |              4500.0 |
| 曉飛      | 15000.0 |             19500.0 |
| 小林      | 20000.0 |             39500.0 |
| 小非      | 23456.0 |             62956.0 |
| 小林      | 24000.0 |             86956.0 |
| 小胡      | 25000.0 |            111956.0 |
| 小肖      | 30000.0 |            141956.0 |
| 小肖      | 35000.0 |            211956.0 |  -- -----| 這兩行同處相同,此時這個視窗的already_paid_salary
| 小肖      | 35000.0 |            211956.0 |  -- -----| = (35000 * 2) (目前兩行) + 141956(前面的行)
| 小東      | 40000.0 |            291956.0 |  -- ---| 這兩行同處相同,此時這個視窗的already_paid_salary
| 張山      | 40000.0 |            291956.0 |  -- ---| = (40000 * 2)(目前兩行) + 211956(之前行的)
| 李四      | 50000.0 |            391956.0 |  -- | 道理同上
| 小張      | 50000.0 |            391956.0 |  -- |
| 王武      | 56000.0 |            503956.0 |  -- ------|道理同上
| 豬小屁    | 56000.0 |            503956.0 |   -- ------|
| 小玉      | 58000.0 |            561956.0 |
+-----------+---------+---------------------+
16 rows in set (0.00 sec)

mysql> SELECT
-> name,
-> salary,
-> SUM(salary) OVER(ORDER BY name)  -- 每個視窗的所有行将根據name進行升序排序這時候,然後不同name的行将會進行累計操作,直接是目前行+以嵌行的,相同的時候,是相同行的和加上之前行的值
-> FROM employee2;
+-----------+---------+---------------------------------+
| name      | salary  | SUM(salary) OVER(ORDER BY name) |
+-----------+---------+---------------------------------+
| 小東      | 40000.0 |                         40000.0 |
| 小五      |  4500.0 |                         44500.0 |
| 小張      | 50000.0 |                         94500.0 |
| 小林      | 24000.0 |                        138500.0 | -- |這兩組同處相同,是以對應的值為(24000 + 20000)(相同的兩行) + 94500(之前的行)
| 小林      | 20000.0 |                        138500.0 | -- |
| 小玉      | 58000.0 |                        196500.0 |
| 小肖      | 30000.0 |                        296500.0 | -- ---|這兩組同處相同,是以對應的值為(30000 + 35000 + 35000)(相同的三行) + 196500(之前的行)
| 小肖      | 35000.0 |                        296500.0 |
| 小肖      | 35000.0 |                        296500.0 | -- ---|
| 小胡      | 25000.0 |                        321500.0 |
| 小非      | 23456.0 |                        344956.0 |
| 張山      | 40000.0 |                        384956.0 |
| 曉飛      | 15000.0 |                        399956.0 |
| 李四      | 50000.0 |                        449956.0 |
| 豬小屁    | 56000.0 |                        505956.0 |
| 王武      | 56000.0 |                        561956.0 |
+-----------+---------+---------------------------------+
16 rows in set (0.00 sec)

           

同時值得注意的是,OVER()是一個全局函數,是以在使用ORDER BY 的時候,那麼最後輸出的時候也将是按照這個有序輸出,但是僅僅在沒有使用PARTITION BY的情況才是這樣的.這個可以從PARTITION BY進行說明,沒有使用PARTITION BY的時候,ORVER()中的ORDER BY将是針對整張表進行排序的,是以這時候如果FROM子句後面的ORDER BY後的字段和OVER()中ORDER BY後的字段相同的時候,就會顯得多此一舉了。 即

# 下面兩個代碼是一樣的,但是僅僅OVER()隻使用ORDER BY子句的時候,并且才這樣
# 兩個ORDER BY後面的字段是相同才可以保證效果一樣
# 如果使用了PARTITION BY子句,那麼OVER()中的ORDER BY将是針對每一個視窗
# 中的所有行進行排序的,而在FROM子句後面的ORDER BY将是針對整張表,是以
# 導緻結果不同
SELECT
name,
SUM(salary) OVER(ORDER BY NAME)
FROM employee2;

SELECT
name,
SUM(salary) OVER(ORDER BY NAME)
FROM employee2
ORDER BY name;

mysql> SELECT
-> name,salary,
-> SUM(salary) OVER(ORDER BY name)
-> FROM employee2;
+-----------+---------+---------------------------------+
| name      | salary  | SUM(salary) OVER(ORDER BY name) |
+-----------+---------+---------------------------------+
| 小東      | 40000.0 |                         40000.0 |
| 小五      |  4500.0 |                         44500.0 |
| 小張      | 50000.0 |                         94500.0 |
| 小林      | 24000.0 |                        138500.0 |
| 小林      | 20000.0 |                        138500.0 |
| 小玉      | 58000.0 |                        196500.0 |
| 小肖      | 30000.0 |                        296500.0 |
| 小肖      | 35000.0 |                        296500.0 |
| 小肖      | 35000.0 |                        296500.0 |
| 小胡      | 25000.0 |                        321500.0 |
| 小非      | 23456.0 |                        344956.0 |
| 張山      | 40000.0 |                        384956.0 |
| 曉飛      | 15000.0 |                        399956.0 |
| 李四      | 50000.0 |                        449956.0 |
| 豬小屁    | 56000.0 |                        505956.0 |
| 王武      | 56000.0 |                        561956.0 |
+-----------+---------+---------------------------------+
16 rows in set (0.00 sec)

# 兩個ORDER BY後面的字段相同時,作用就會相當隻使用SUM(salary) OVER(ORDER BY name)
mysql> SELECT
-> name,salary,
-> SUM(salary) OVER(ORDER BY name)
-> FROM employee2
-> ORDER BY name;
+-----------+---------+---------------------------------+
| name      | salary  | SUM(salary) OVER(ORDER BY name) |
+-----------+---------+---------------------------------+
| 小東      | 40000.0 |                         40000.0 |
| 小五      |  4500.0 |                         44500.0 |
| 小張      | 50000.0 |                         94500.0 |
| 小林      | 24000.0 |                        138500.0 |
| 小林      | 20000.0 |                        138500.0 |
| 小玉      | 58000.0 |                        196500.0 |
| 小肖      | 30000.0 |                        296500.0 |
| 小肖      | 35000.0 |                        296500.0 |
| 小肖      | 35000.0 |                        296500.0 |
| 小胡      | 25000.0 |                        321500.0 |
| 小非      | 23456.0 |                        344956.0 |
| 張山      | 40000.0 |                        384956.0 |
| 曉飛      | 15000.0 |                        399956.0 |
| 李四      | 50000.0 |                        449956.0 |
| 豬小屁    | 56000.0 |                        505956.0 |
| 王武      | 56000.0 |                        561956.0 |
+-----------+---------+---------------------------------+
16 rows in set (0.00 sec)

# 兩個ORDER BY後的字段不同,那麼FROM 子句後的ORDER BY将會覆寫OVER()中的ORDER BY
mysql> SELECT
-> name,salary,
-> SUM(salary) OVER(ORDER BY name)
-> FROM employee2
-> ORDER BY salary;
+-----------+---------+---------------------------------+
| name      | salary  | SUM(salary) OVER(ORDER BY name) |
+-----------+---------+---------------------------------+
| 小五      |  4500.0 |                         44500.0 |
| 曉飛      | 15000.0 |                        399956.0 |
| 小林      | 20000.0 |                        138500.0 |
| 小非      | 23456.0 |                        344956.0 |
| 小林      | 24000.0 |                        138500.0 |
| 小胡      | 25000.0 |                        321500.0 |
| 小肖      | 30000.0 |                        296500.0 |
| 小肖      | 35000.0 |                        296500.0 |
| 小肖      | 35000.0 |                        296500.0 |
| 小東      | 40000.0 |                         40000.0 |
| 張山      | 40000.0 |                        384956.0 |
| 小張      | 50000.0 |                         94500.0 |
| 李四      | 50000.0 |                        449956.0 |
| 豬小屁    | 56000.0 |                        505956.0 |
| 王武      | 56000.0 |                        561956.0 |
| 小玉      | 58000.0 |                        196500.0 |
+-----------+---------+---------------------------------+
16 rows in set (0.00 sec)

# OVER()中的ORDER BY針對的視窗中的所有行進行排序的,而下面的FROM子句中的
# ORDER BY是針對整個表的,是以此時兩者的作用并不相同
mysql> SELECT
-> name,salary,
-> SUM(salary) OVER(PARTITION BY dept_id ORDER BY name)
-> FROM employee2;
+-----------+---------+------------------------------------------------------+
| name      | salary  | SUM(salary) OVER(PARTITION BY dept_id ORDER BY name) |
+-----------+---------+------------------------------------------------------+
| 小五      |  4500.0 |                                               4500.0 |
| 小林      | 24000.0 |                                              28500.0 |
| 小張      | 50000.0 |                                              50000.0 |
| 小玉      | 58000.0 |                                             108000.0 |
| 小肖      | 30000.0 |                                             173000.0 |
| 小肖      | 35000.0 |                                             173000.0 |
| 張山      | 40000.0 |                                             213000.0 |
| 李四      | 50000.0 |                                             263000.0 |
| 小東      | 40000.0 |                                              40000.0 |
| 小林      | 20000.0 |                                              60000.0 |
| 小肖      | 35000.0 |                                              95000.0 |
| 小胡      | 25000.0 |                                             120000.0 |
| 豬小屁    | 56000.0 |                                             176000.0 |
| 王武      | 56000.0 |                                             232000.0 |
| 小非      | 23456.0 |                                              23456.0 |
| 曉飛      | 15000.0 |                                              15000.0 |
+-----------+---------+------------------------------------------------------+
16 rows in set (0.00 sec)

mysql> SELECT
-> name,salary,
-> SUM(salary) OVER(PARTITION BY dept_id ORDER BY name)
-> FROM employee2
-> ORDER BY name;
+-----------+---------+------------------------------------------------------+
| name      | salary  | SUM(salary) OVER(PARTITION BY dept_id ORDER BY name) |
+-----------+---------+------------------------------------------------------+
| 小東      | 40000.0 |                                              40000.0 |
| 小五      |  4500.0 |                                               4500.0 |
| 小張      | 50000.0 |                                              50000.0 |
| 小林      | 24000.0 |                                              28500.0 |
| 小林      | 20000.0 |                                              60000.0 |
| 小玉      | 58000.0 |                                             108000.0 |
| 小肖      | 30000.0 |                                             173000.0 |
| 小肖      | 35000.0 |                                             173000.0 |
| 小肖      | 35000.0 |                                              95000.0 |
| 小胡      | 25000.0 |                                             120000.0 |
| 小非      | 23456.0 |                                              23456.0 |
| 張山      | 40000.0 |                                             213000.0 |
| 曉飛      | 15000.0 |                                              15000.0 |
| 李四      | 50000.0 |                                             263000.0 |
| 豬小屁    | 56000.0 |                                             176000.0 |
| 王武      | 56000.0 |                                             232000.0 |
+-----------+---------+------------------------------------------------------+
16 rows in set (0.00 sec)

           
  • OVER(PARTITION BY yyy ORDER BY zzz ASC\DESC):根據PARTITION BY ,此時表示根據yyy進行分組,然後在每個視窗中的所有行将利用ORDER BY 子句,将根據zzz進行排序。值得注意的是,如果zzz和yyy相同的時候,這時候作用相當于OVER(PARTITION BY yyy),和沒有ORDER BY子句是一樣的,因為都處在一個視窗了。
mysql> SELECT
-> name,
-> salary,
-> SUM(salary) OVER(PARTITION BY dept_id)
-> FROM employee2;
+-----------+---------+----------------------------------------+
| name      | salary  | SUM(salary) OVER(PARTITION BY dept_id) |
+-----------+---------+----------------------------------------+
| 小林      | 24000.0 |                                28500.0 |  -- | 分組為dept_id = NULL的
| 小五      |  4500.0 |                                28500.0 |  -- |
| 小肖      | 30000.0 |                               263000.0 |  ------|
| 張山      | 40000.0 |                               263000.0 |
| 李四      | 50000.0 |                               263000.0 |
| 小玉      | 58000.0 |                               263000.0 |       -- 分組為dept_id = 1的
| 小張      | 50000.0 |                               263000.0 |
| 小肖      | 35000.0 |                               263000.0 |  ------|
| 小東      | 40000.0 |                               232000.0 |  --------|
| 小肖      | 35000.0 |                               232000.0 |
| 王武      | 56000.0 |                               232000.0 |
| 豬小屁    | 56000.0 |                               232000.0 |        -- 分組為dept_id = 2的
| 小胡      | 25000.0 |                               232000.0 |
| 小林      | 20000.0 |                               232000.0 |  --------|
| 小非      | 23456.0 |                                23456.0 |  -- ---------| 分組為dept_id = 3的
| 曉飛      | 15000.0 |                                15000.0 |  -- ------------| 分組為dept_id = 4的
+-----------+---------+----------------------------------------+
16 rows in set (0.00 sec)

mysql> SELECT
-> name,
-> salary,
-> SUM(salary) OVER(PARTITION BY dept_id ORDER BY dept_id)
-> FROM employee2;
+-----------+---------+---------------------------------------------------------+
| name      | salary  | SUM(salary) OVER(PARTITION BY dept_id ORDER BY dept_id) |
+-----------+---------+---------------------------------------------------------+
| 小林      | 24000.0 |                                                 28500.0 |
| 小五      |  4500.0 |                                                 28500.0 |
| 小肖      | 30000.0 |                                                263000.0 |
| 張山      | 40000.0 |                                                263000.0 |
| 李四      | 50000.0 |                                                263000.0 |
| 小玉      | 58000.0 |                                                263000.0 |
| 小張      | 50000.0 |                                                263000.0 |
| 小肖      | 35000.0 |                                                263000.0 |
| 小東      | 40000.0 |                                                232000.0 |
| 小肖      | 35000.0 |                                                232000.0 |
| 王武      | 56000.0 |                                                232000.0 |
| 豬小屁    | 56000.0 |                                                232000.0 |
| 小胡      | 25000.0 |                                                232000.0 |
| 小林      | 20000.0 |                                                232000.0 |
| 小非      | 23456.0 |                                                 23456.0 |
| 曉飛      | 15000.0 |                                                 15000.0 |
+-----------+---------+---------------------------------------------------------+
16 rows in set (0.00 sec)

# 注意檢視dept_id = 1視窗中的name = "小肖"的值
mysql> SELECT
-> name,salary,
-> SUM(salary) OVER(PARTITION BY dept_id ORDER BY name)
-> FROM employee2;
+-----------+---------+------------------------------------------------------+
| name      | salary  | SUM(salary) OVER(PARTITION BY dept_id ORDER BY name) |
+-----------+---------+------------------------------------------------------+
| 小五      |  4500.0 |                                               4500.0 |
| 小林      | 24000.0 |                                              28500.0 |
| 小張      | 50000.0 |                                              50000.0 |
| 小玉      | 58000.0 |                                             108000.0 |
| 小肖      | 30000.0 |                                             173000.0 |
| 小肖      | 35000.0 |                                             173000.0 |
| 張山      | 40000.0 |                                             213000.0 |
| 李四      | 50000.0 |                                             263000.0 |
| 小東      | 40000.0 |                                              40000.0 |
| 小林      | 20000.0 |                                              60000.0 |
| 小肖      | 35000.0 |                                              95000.0 |
| 小胡      | 25000.0 |                                             120000.0 |
| 豬小屁    | 56000.0 |                                             176000.0 |
| 王武      | 56000.0 |                                             232000.0 |
| 小非      | 23456.0 |                                              23456.0 |
| 曉飛      | 15000.0 |                                              15000.0 |
+-----------+---------+------------------------------------------------------+
16 rows in set (0.00 sec)

           

而視窗函數可以和SUM()\AVG()\COUNT()\MAX()\MIN()這幾個函數一起使用: 其中這些函數有一些特點,如果AVG()\COUNT()\MAX()\MIN()的括号中必須要有參數,用于統計某一列的對應的值,并且這一列中如果含有值為NULL的行,那麼就會忽略值NULL的行,而COUNT()則比較特殊,如果是COUNT(*),那麼就不會忽略NULL值的行,用來統計這個表中有多少行,否則,如果是COUNT(column),統計某一列column有多少行,那麼就會忽略NULL的行。

如果需要指定AVG()等小數的輸出格式,則需要使用下面幾個函數:

  • FORMAT(xxx,yyy,zzz)指定xxx有yyy個小數。但是這個函數有個特點,就是整數部分每三個數字就會用分隔符隔開(從小數點左邊第一個數開始算的),如果不寫zzz這個參數,即隻有兩個參數,就會以,作為分隔符了。例如45000,如果利用FORMAT(45000,2),最後得到的是45,000.00的形式,再例如FORMAT(45000,4),得到的是45,000.0000
# 利用FORMAT,進而指定小數最後保留多少個小數點,同時從小數點左邊第一個數字往左算,每三個數字
# 就會有一個分隔符.注意的是,原本FORMAT()有三個參數,如果不寫zzz這個參數,就會預設用','作
# 為分隔符
mysql> SELECT
-> name,
-> FORMAT(salary,4)
-> FROM employee2;
+-----------+------------------+
| name      | FORMAT(salary,4) |
+-----------+------------------+
| 小肖      | 30,000.0000      |
| 小東      | 40,000.0000      |
| 小非      | 23,456.0000      |
| 曉飛      | 15,000.0000      |
| 小林      | 24,000.0000      |
| 小五      | 4,500.0000       |
| 張山      | 40,000.0000      |
| 小肖      | 35,000.0000      |
| 李四      | 50,000.0000      |
| 王武      | 56,000.0000      |
| 豬小屁    | 56,000.0000      |
| 小玉      | 58,000.0000      |
| 小張      | 50,000.0000      |
| 小胡      | 25,000.0000      |
| 小肖      | 35,000.0000      |
| 小林      | 20,000.0000      |
+-----------+------------------+
16 rows in set (0.00 sec)

           
  • CAST(xxx AS decimal(12,yyy)):指定xxx有yyy個小數.作用和CONVERT()一樣,指定xxx有yyy個小數,但是和FORMAT()不同,他并不會每3個數字就用逗号隔開,例如45000,指定輸出3個小數,則CONVERT(45000,DECIMAL(12,3)),将會輸出45000.0,并沒有逗号隔開.
mysql> SELECT
-> name,
-> CAST(salary AS DECIMAL(12,3)) -- 使用CAST,這時候相當于CONVERT一樣,指定有多少個小數,并且不會出現分隔符
-> FROM employee2;
+-----------+-------------------------------+
| name      | CAST(salary AS DECIMAL(12,3)) |
+-----------+-------------------------------+
| 小肖      |                     30000.000 |
| 小東      |                     40000.000 |
| 小非      |                     23456.000 |
| 曉飛      |                     15000.000 |
| 小林      |                     24000.000 |
| 小五      |                      4500.000 |
| 張山      |                     40000.000 |
| 小肖      |                     35000.000 |
| 李四      |                     50000.000 |
| 王武      |                     56000.000 |
| 豬小屁    |                     56000.000 |
| 小玉      |                     58000.000 |
| 小張      |                     50000.000 |
| 小胡      |                     25000.000 |
| 小肖      |                     35000.000 |
| 小林      |                     20000.000 |
+-----------+-------------------------------+
16 rows in set (0.00 sec)

           
  • CONVERT(xxx,DECIMAL(12,yyy)):指定xxx有yyy個小數,但是和FORMAT()不同,他并不會每3個數字就用逗号隔開,例如45000,指定輸出3個小數,則CONVERT(45000,DECIMAL(12,3)),将會輸出45000.0,并沒有逗号隔開.
# 利用CONVERT,在指定有多少個小數的同時,不會出現逗号這樣的分隔符,即從小數點左邊的第一個數
# 字開始算,每三個數字并不會向FORMAT一樣出現分隔符
mysql> SELECT
-> name,
-> CONVERT(salary,DECIMAL(12,3))
-> FROM employee2;
+-----------+-------------------------------+
| name      | CONVERT(salary,DECIMAL(12,3)) |
+-----------+-------------------------------+
| 小肖      |                     30000.000 |
| 小東      |                     40000.000 |
| 小非      |                     23456.000 |
| 曉飛      |                     15000.000 |
| 小林      |                     24000.000 |
| 小五      |                      4500.000 |
| 張山      |                     40000.000 |
| 小肖      |                     35000.000 |
| 李四      |                     50000.000 |
| 王武      |                     56000.000 |
| 豬小屁    |                     56000.000 |
| 小玉      |                     58000.000 |
| 小張      |                     50000.000 |
| 小胡      |                     25000.000 |
| 小肖      |                     35000.000 |
| 小林      |                     20000.000 |
+-----------+-------------------------------+
16 rows in set (0.00 sec)

           

此外,上面三個函數除了分隔符差別外,還有的是在ORDER BY方面,因為FORMAT得到的是一個字元串,是以利用ORDER BY 的時候,此時是基于字典順序進行排序的,而CONVERT\CAST得到的是一個數字,是以利用ORDER BY 的時候,依舊是按照數字進行排序的。

# 利用CAST,然後利用這個列進行排序輸出,由于CAST得到的是一個數字,是以利用ORDER BY
# 的時候,就是按照數字大小進行排序的
mysql> SELECT
-> name,
-> CAST(salary AS DECIMAL(12,3)) AS cast_salary
-> FROM employee2
-> ORDER BY cast_salary;
+-----------+-------------+
| name      | cast_salary |
+-----------+-------------+
| 小五      |    4500.000 |
| 曉飛      |   15000.000 |
| 小林      |   20000.000 |
| 小非      |   23456.000 |
| 小林      |   24000.000 |
| 小胡      |   25000.000 |
| 小肖      |   30000.000 |
| 小肖      |   35000.000 |
| 小肖      |   35000.000 |
| 小東      |   40000.000 |
| 張山      |   40000.000 |
| 李四      |   50000.000 |
| 小張      |   50000.000 |
| 王武      |   56000.000 |
| 豬小屁    |   56000.000 |
| 小玉      |   58000.000 |
+-----------+-------------+
16 rows in set (0.00 sec)

# 利用FORMAT,然後利用這個列進行排序輸出,由于FORMAT得到的是一個字元串,是以利用ORDER BY
# 的時候,就是按照字典順序進行排序的
mysql> SELECT
-> name,
-> FORMAT(salary,3) AS format_salary
-> FROM employee2
-> ORDER BY format_salary;
+-----------+---------------+
| name      | format_salary |
+-----------+---------------+
| 曉飛      | 15,000.000    |
| 小林      | 20,000.000    |
| 小非      | 23,456.000    |
| 小林      | 24,000.000    |
| 小胡      | 25,000.000    |
| 小肖      | 30,000.000    |
| 小肖      | 35,000.000    |
| 小肖      | 35,000.000    |
| 小五      | 4,500.000     |
| 小東      | 40,000.000    |
| 張山      | 40,000.000    |
| 李四      | 50,000.000    |
| 小張      | 50,000.000    |
| 王武      | 56,000.000    |
| 豬小屁    | 56,000.000    |
| 小玉      | 58,000.000    |
+-----------+---------------+
16 rows in set (0.00 sec)

# 利用CONVERT,然後利用這個列進行排序輸出,由于CONVERT得到的是一個數字,是以利用ORDER BY
# 的時候,就是按照數字大小進行排序的
mysql> SELECT
-> name,
-> CONVERT(salary,DECIMAL(12,3)) AS convert_salary
-> FROM employee2
-> ORDER BY convert_salary;
+-----------+----------------+
| name      | convert_salary |
+-----------+----------------+
| 小五      |       4500.000 |
| 曉飛      |      15000.000 |
| 小林      |      20000.000 |
| 小非      |      23456.000 |
| 小林      |      24000.000 |
| 小胡      |      25000.000 |
| 小肖      |      30000.000 |
| 小肖      |      35000.000 |
| 小肖      |      35000.000 |
| 小東      |      40000.000 |
| 張山      |      40000.000 |
| 李四      |      50000.000 |
| 小張      |      50000.000 |
| 王武      |      56000.000 |
| 豬小屁    |      56000.000 |
| 小玉      |      58000.000 |
+-----------+----------------+
16 rows in set (0.00 sec)

           

這一題中就有講到輸出的格式:考試分數(一)

值得一提的是,MAX()\MIN()不僅可以求解數值和日期的最值,同時可以求解文本的最值。

這裡主要講一下SUM()和視窗函數使用:SUM(xxx) OVER(PARTITION BY yyy ORDER BY zzz) :這個是根據yyy進行分組,進而劃分成為了多個視窗,這些視窗根據zzz進行排序,然後每個視窗将進行連續累計xxx。

下面這一題就是運用到了SUM()函數與視窗函數OVER()一起使用了: 統計salary的累計和running_total 最差是第幾名

視窗函數還可以和排序函數一起使用

  • ROW_NUMBER() OVER():直接表示第幾行了,并不會出現并列的情況
  • DENSE_RANK() OVER():并列連續
  • RANK() OVER():并列不連續
# ROW_NUMBER() OVER() 直接表示第幾行
mysql>  SELECT
-> name,
-> salary,
-> ROW_NUMBER() OVER(ORDER BY salary DESC)
-> FROM employee2;
+-----------+---------+-----------------------------------------+
| name      | salary  | ROW_NUMBER() OVER(ORDER BY salary DESC) |
+-----------+---------+-----------------------------------------+
| 小玉      | 58000.0 |                                       1 |
| 王武      | 56000.0 |                                       2 |
| 豬小屁    | 56000.0 |                                       3 |
| 李四      | 50000.0 |                                       4 |
| 小張      | 50000.0 |                                       5 |
| 小東      | 40000.0 |                                       6 |
| 張山      | 40000.0 |                                       7 |
| 小肖      | 35000.0 |                                       8 |
| 小肖      | 35000.0 |                                       9 |
| 小肖      | 30000.0 |                                      10 |
| 小胡      | 25000.0 |                                      11 |
| 小林      | 24000.0 |                                      12 |
| 小非      | 23456.0 |                                      13 |
| 小林      | 20000.0 |                                      14 |
| 曉飛      | 15000.0 |                                      15 |
| 小五      |  4500.0 |                                      16 |
+-----------+---------+-----------------------------------------+
16 rows in set (0.00 sec)
# RANK() OVER() 表示并列,但是不會連續
mysql> SELECT
-> name,
-> salary,
-> RANK() OVER(ORDER BY salary DESC) -- 根據salary降序進行排序
-> FROM employee2;
+-----------+---------+-----------------------------------+
| name      | salary  | RANK() OVER(ORDER BY salary DESC) |
+-----------+---------+-----------------------------------+
| 小玉      | 58000.0 |                                 1 |
| 王武      | 56000.0 |                                 2 |  -- --| 這兩組同處于第2,但是不會連續,是以下一組是
| 豬小屁    | 56000.0 |                                 2 |  -- --| 從4開始了
| 李四      | 50000.0 |                                 4 |
| 小張      | 50000.0 |                                 4 |
| 小東      | 40000.0 |                                 6 |
| 張山      | 40000.0 |                                 6 |
| 小肖      | 35000.0 |                                 8 |
| 小肖      | 35000.0 |                                 8 |
| 小肖      | 30000.0 |                                10 |
| 小胡      | 25000.0 |                                11 |
| 小林      | 24000.0 |                                12 |
| 小非      | 23456.0 |                                13 |
| 小林      | 20000.0 |                                14 |
| 曉飛      | 15000.0 |                                15 |
| 小五      |  4500.0 |                                16 |
+-----------+---------+-----------------------------------+
16 rows in set (0.00 sec)
# DENSE_RANK() OVER() 并列連續排序
mysql> SELECT
-> name,
-> salary,
-> DENSE_RANK() OVER(ORDER BY salary DESC)
-> FROM employee2;
+-----------+---------+-----------------------------------------+
| name      | salary  | DENSE_RANK() OVER(ORDER BY salary DESC) |
+-----------+---------+-----------------------------------------+
| 小玉      | 58000.0 |                                       1 |
| 王武      | 56000.0 |                                       2 | -- |這兩組并列第2,并且是連續排序的
| 豬小屁    | 56000.0 |                                       2 | -- |是以下一組是從3開始的
| 李四      | 50000.0 |                                       3 |
| 小張      | 50000.0 |                                       3 |
| 小東      | 40000.0 |                                       4 |
| 張山      | 40000.0 |                                       4 |
| 小肖      | 35000.0 |                                       5 |
| 小肖      | 35000.0 |                                       5 |
| 小肖      | 30000.0 |                                       6 |
| 小胡      | 25000.0 |                                       7 |
| 小林      | 24000.0 |                                       8 |
| 小非      | 23456.0 |                                       9 |
| 小林      | 20000.0 |                                      10 |
| 曉飛      | 15000.0 |                                      11 |
| 小五      |  4500.0 |                                      12 |
+-----------+---------+-----------------------------------------+
16 rows in set (0.00 sec)

           

此外視窗函數還可以和其他一些函數使用,這裡就不列舉了。

繼續閱讀