8.1 窗口函数
8.1 根据不同的种类,销售单价由高到低排列RANK
postgres=# SELECT product_name,product_type,sale_price,
postgres-# RANK () OVER (PARTITION BY product_type
postgres(# ORDER BY sale_price) AS ranking
postgres-# FROM Product;
product_name | product_type | sale_price | ranking
--------------+--------------+------------+---------
圆珠笔 | 办公用品 | 100 | 1
打孔器 | 办公用品 | 500 | 2
叉子 | 厨房用具 | 500 | 1
擦菜板 | 厨房用具 | 880 | 2
菜刀 | 厨房用具 | 3000 | 3
高压锅 | 厨房用具 | 6800 | 4
T恤 | 衣服 | 1000 | 1
运动T恤 | 衣服 | 4000 | 2
(8 行记录)
8.3 使用RANK,DENSE_RANK或ROW_NUMBER排序的区别
postgres=# SELECT product_name,product_type,sale_price,
postgres-# RANK () OVER (ORDER BY sale_price) AS ranking,
postgres-# DENSE_RANK () OVER (ORDER BY sale_price) AS dense_ranking,
postgres-# ROW_NUMBER () OVER (ORDER BY sale_price) AS row_ranking
postgres-# FROM Product;
product_name | product_type | sale_price | ranking | dense_ranking | row_ranking
--------------+--------------+------------+---------+---------------+-------------
圆珠笔 | 办公用品 | 100 | 1 | 1 | 1
叉子 | 厨房用具 | 500 | 2 | 2 | 2
打孔器 | 办公用品 | 500 | 2 | 2 | 3
擦菜板 | 厨房用具 | 880 | 4 | 3 | 4
T恤 | 衣服 | 1000 | 5 | 4 | 5
菜刀 | 厨房用具 | 3000 | 6 | 5 | 6
运动T恤 | 衣服 | 4000 | 7 | 6 | 7
高压锅 | 厨房用具 | 6800 | 8 | 7 | 8
(8 行记录)
注:窗口函数的使用位置:SELECT子句当中
8.4 SUM作为窗口函数
postgres=# SELECT product_id,product_name,sale_price,
postgres-# SUM (sale_price) OVER (ORDER BY product_id) AS current_sum
postgres-# FROM Product;
product_id | product_name | sale_price | current_sum
------------+--------------+------------+-------------
0001 | T恤 | 1000 | 1000
0002 | 打孔器 | 500 | 1500
0003 | 运动T恤 | 4000 | 5500
0004 | 菜刀 | 3000 | 8500
0005 | 高压锅 | 6800 | 15300
0006 | 叉子 | 500 | 15800
0007 | 擦菜板 | 880 | 16680
0008 | 圆珠笔 | 100 | 16780
(8 行记录)
8.5 AVG 函数作为窗口函数
postgres=# SELECT product_id,product_name,sale_price,
postgres-# AVG(sale_price) OVER (ORDER BY product_id) AS avg_price
postgres-# FROM Product;
product_id | product_name | sale_price | avg_price
------------+--------------+------------+-----------------------
0001 | T恤 | 1000 | 1000.0000000000000000
0002 | 打孔器 | 500 | 750.0000000000000000
0003 | 运动T恤 | 4000 | 1833.3333333333333333
0004 | 菜刀 | 3000 | 2125.0000000000000000
0005 | 高压锅 | 6800 | 3060.0000000000000000
0006 | 叉子 | 500 | 2633.3333333333333333
0007 | 擦菜板 | 880 | 2382.8571428571428571
0008 | 圆珠笔 | 100 | 2097.5000000000000000
(8 行记录)
8.6 指定最靠近3行作为汇总对象
postgres=# SELECT product_id,product_name,sale_price,
postgres-# AVG(sale_price) OVER (ORDER BY product_id
postgres(# ROWS 2 PRECEDING) AS avg_p2
postgres-# FROM Product;
product_id | product_name | sale_price | avg_p2
------------+--------------+------------+-----------------------
0001 | T恤 | 1000 | 1000.0000000000000000
0002 | 打孔器 | 500 | 750.0000000000000000
0003 | 运动T恤 | 4000 | 1833.3333333333333333
0004 | 菜刀 | 3000 | 2500.0000000000000000
0005 | 高压锅 | 6800 | 4600.0000000000000000
0006 | 叉子 | 500 | 3433.3333333333333333
0007 | 擦菜板 | 880 | 2726.6666666666666667
0008 | 圆珠笔 | 100 | 493.3333333333333333
(8 行记录)
8.7 将当前记录的前后作为汇总对象
postgres=# SELECT product_id,product_name,sale_price,
postgres-# AVG(sale_price) OVER (ORDER BY product_id
postgres(# ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) AS avg_3
postgres-# FROM Product;
product_id | product_name | sale_price | avg_3
------------+--------------+------------+-----------------------
0001 | T恤 | 1000 | 750.0000000000000000
0002 | 打孔器 | 500 | 1833.3333333333333333
0003 | 运动T恤 | 4000 | 2500.0000000000000000
0004 | 菜刀 | 3000 | 4600.0000000000000000
0005 | 高压锅 | 6800 | 3433.3333333333333333
0006 | 叉子 | 500 | 2726.6666666666666667
0007 | 擦菜板 | 880 | 493.3333333333333333
0008 | 圆珠笔 | 100 | 490.0000000000000000
(8 行记录)
8.8 想要结果是按照ranking的顺序,还得使用ORDER BY在语句末尾
postgres=# SELECT product_id,product_name,sale_price,
postgres-# RANK () OVER (ORDER BY sale_price) AS ranking
postgres-# FROM Product
postgres-# ORDER BY ranking;
product_id | product_name | sale_price | ranking
------------+--------------+------------+---------
0008 | 圆珠笔 | 100 | 1
0006 | 叉子 | 500 | 2
0002 | 打孔器 | 500 | 2
0007 | 擦菜板 | 880 | 4
0001 | T恤 | 1000 | 5
0004 | 菜刀 | 3000 | 6
0003 | 运动T恤 | 4000 | 7
0005 | 高压锅 | 6800 | 8
(8 行记录)
8.11 UNION ALL连接汇总行和小结
postgres=# SELECT '合计' AS product_type,SUM(sale_price)
postgres-# FROM Product
postgres-# UNION ALL
postgres-# SELECT product_type,SUM(sale_price)
postgres-# FROM Product
postgres-# GROUP BY product_type;
product_type | sum
--------------+-------
合计 | 16780
衣服 | 5000
办公用品 | 600
厨房用具 | 11180
(4 行记录)
GROUPING :ROLLUP,CUBE,GROUPING SETS
8.12 使用ROLLUP同时得出合计和小计
postgres=# SELECT product_type,SUM(sale_price) AS sum_price
postgres-# FROM product
postgres-# GROUP BY ROLLUP (product_type);
product_type | sum_price
--------------+-----------
办公用品 | 600
厨房用具 | 11180
衣服 | 5000
| 16780
(4 行记录)
8.14 在GROUP中添加登记日期
postgres=# SELECT product_type, regist_date, SUM(sale_price) AS sum_price
postgres-# FROM Product
postgres-# GROUP BY ROLLUP(product_type,regist_date);
product_type | regist_date | sum_price
--------------+-------------+-----------
办公用品 | 2009-09-11 | 500
办公用品 | 2009-11-11 | 100
办公用品 | | 600
厨房用具 | 2008-04-28 | 880
厨房用具 | 2009-01-15 | 6800
厨房用具 | 2009-09-20 | 3500
厨房用具 | | 11180
衣服 | 2009-09-20 | 1000
衣服 | | 4000
衣服 | | 5000
| | 16780
(11 行记录)
8.15 用GROUPING 判断是否为NULL
postgres=# SELECT GROUPING(product_type) AS product_type,
postgres-# GROUPING(regist_date) AS regist_date,SUM(sale_price) AS sum_price
postgres-# FROM Product
postgres-# GROUP BY ROLLUP(product_type,regist_date);
product_type | regist_date | sum_price
--------------+-------------+-----------
0 | 0 | 500
0 | 0 | 100
0 | 1 | 600
0 | 0 | 880
0 | 0 | 6800
0 | 0 | 3500
0 | 1 | 11180
0 | 0 | 1000
0 | 0 | 4000
0 | 1 | 5000
1 | 1 | 16780
(11 行记录)
8.16 在超级分组记录中插入需要的字符串
postgres=# SELECT CASE WHEN GROUPING(product_type) = 1
postgres-# THEN '商品种类 合计'
postgres-# ELSE product_type END AS product_type,
postgres-# CASE WHEN GROUPING(regist_date) = 1
postgres-# THEN '登记日期 合计'
postgres-# ELSE CAST(regist_date AS VARCHAR(16)) END AS regist_date,
postgres-# SUM(sale_price) AS sum_price
postgres-# FROM Product
postgres-# GROUP BY ROLLUP(product_type, regist_date);
product_type | regist_date | sum_price
---------------+---------------+-----------
办公用品 | 2009-09-11 | 500
办公用品 | 2009-11-11 | 100
办公用品 | 登记日期 合计 | 600
厨房用具 | 2008-04-28 | 880
厨房用具 | 2009-01-15 | 6800
厨房用具 | 2009-09-20 | 3500
厨房用具 | 登记日期 合计 | 11180
衣服 | 2009-09-20 | 1000
衣服 | | 4000
衣服 | 登记日期 合计 | 5000
商品种类 合计 | 登记日期 合计 | 16780
8.17 使用CUBE代替ROLLUP取得全部组合的结果
postgres=# SELECT CASE WHEN GROUPING(product_type) = 1
postgres-# THEN '商品种类 合计'
postgres-# ELSE product_type END AS product_type,
postgres-# CASE WHEN GROUPING(regist_date) = 1
postgres-# THEN '登记日期 合计'
postgres-# ELSE CAST(regist_date AS VARCHAR(16)) END AS regist_date,
postgres-# SUM(sale_price) AS sum_price
postgres-# FROM Product
postgres-# GROUP BY CUBE(product_type,regist_date);
product_type | regist_date | sum_price
---------------+---------------+-----------
办公用品 | 2009-09-11 | 500
办公用品 | 2009-11-11 | 100
办公用品 | 登记日期 合计 | 600
厨房用具 | 2008-04-28 | 880
厨房用具 | 2009-01-15 | 6800
厨房用具 | 2009-09-20 | 3500
厨房用具 | 登记日期 合计 | 11180
衣服 | 2009-09-20 | 1000
衣服 | | 4000
衣服 | 登记日期 合计 | 5000
商品种类 合计 | 登记日期 合计 | 16780
商品种类 合计 | 2008-04-28 | 880
商品种类 合计 | 2009-01-15 | 6800
商品种类 合计 | 2009-09-11 | 500
商品种类 合计 | 2009-09-20 | 4500
商品种类 合计 | 2009-11-11 | 100
商品种类 合计 | | 4000
(17 行记录)
8.18 使用GROUPING SETS取得部分组合的结果
postgres=# SELECT CASE WHEN GROUPING(product_type) = 1
postgres-# THEN '商品种类 合计'
postgres-# ELSE product_type END AS product_type,
postgres-# CASE WHEN GROUPING(regist_date) = 1
postgres-# THEN '登记日期 合计'
postgres-# ELSE CAST(regist_date AS VARCHAR(16)) END AS regist_date,
postgres-# SUM(sale_price) AS sum_tanka
postgres-# FROM Product
postgres-# GROUP BY GROUPING SETS (product_type, regist_date);
product_type | regist_date | sum_tanka
---------------+---------------+-----------
办公用品 | 登记日期 合计 | 600
厨房用具 | 登记日期 合计 | 11180
衣服 | 登记日期 合计 | 5000
商品种类 合计 | 2008-04-28 | 880
商品种类 合计 | 2009-01-15 | 6800
商品种类 合计 | 2009-09-11 | 500
商品种类 合计 | 2009-09-20 | 4500
商品种类 合计 | 2009-11-11 | 100
商品种类 合计 | | 4000
(9 行记录)
练习:
postgres=# SELECT regist_date,product_name,sale_price,
postgres-# SUM(sale_price) OVER(ORDER BY regist_date NULLS FIRST) AS sum_sale_price
postgres-# FROM Product;
regist_date | product_name | sale_price | sum_sale_price
-------------+--------------+------------+----------------
| 运动T恤 | 4000 | 4000
2008-04-28 | 擦菜板 | 880 | 4880
2009-01-15 | 高压锅 | 6800 | 11680
2009-09-11 | 打孔器 | 500 | 12180
2009-09-20 | T恤 | 1000 | 16680
2009-09-20 | 菜刀 | 3000 | 16680
2009-09-20 | 叉子 | 500 | 16680
2009-11-11 | 圆珠笔 | 100 | 16780
(8 行记录)