学习笔记与练习 | SQL入门(五)|SQL高级处理


窗口函数

窗口函数也称为OLAP函数。OLAP 是OnLine AnalyticalProcessing 的简称,意思是对数据库数据进行实时分析处理。
窗口函数的通用形式:

<窗口函数> OVER ([PARTITION BY <列名>]
                     ORDER BY <排序用列名>) 

*[]中的内容可以省略。

  • PARTITON BY是用来分组,即选择要看哪个窗口,类似于GROUP BY 子句的分组功能,但是PARTITION BY子句并不具备GROUP BY 子句的汇总功能,并不会改变原始表中记录的行数
  • ORDER BY是用来排序,即决定窗口内,是按哪种规则(字段)来排序的。
  • 窗口函数中的ORDER BYSELECT语句末尾的ORDER BY一样,可以通过关键字ASC/DESC来指定升序/降序。省略该关键字时会默认按照ASC

窗口函数种类

专用窗口函数

RANK()函数
计算排序时,如果存在相同位次的记录,则会跳过之后的位次。
有 3 条记录排在第 1 位时:1 位、1 位、1 位、4 位……

DENSE_RANK()函数
同样是计算排序,即使存在相同位次的记录,也不会跳过之后的位次。
有 3 条记录排在第 1 位时:1 位、1 位、1 位、2 位……

ROW_NUMBER()函数
赋予唯一的连续位次。
有 3 条记录排在第 1 位时:1 位、2 位、3 位、4 位

例子:

SELECT  product_name
       ,product_type
       ,sale_price
       ,RANK() OVER (ORDER BY sale_price) AS ranking
       ,DENSE_RANK() OVER (ORDER BY sale_price) AS dense_ranking
       ,ROW_NUMBER() OVER (ORDER BY sale_price) AS row_num
  FROM product  

聚合函数(窗口)

当前所在行及之前所有的行的合计或均值,即累计到当前行的聚合。

SELECT  product_id
       ,product_name
       ,sale_price
       ,SUM(sale_price) OVER (ORDER BY product_id) AS current_sum
       ,AVG(sale_price) OVER (ORDER BY product_id) AS current_avg  
  FROM product;  

那么如果想更改累计的行应该尝试计算移动平均,规则如下:

  • PRECEDING(“之前”), 将框架指定为 “截止到之前 n 行”,加上自身行
  • FOLLOWING(“之后”), 将框架指定为 “截止到之后 n 行”,加上自身行
<窗口函数> OVER (ORDER BY <排序用列名>
                 ROWS n PRECEDING )  
                 
<窗口函数> OVER (ORDER BY <排序用列名>
                 ROWS BETWEEN n PRECEDING AND n FOLLOWING)

窗口函数适用范围和注意事项

  • 原则上,窗口函数只能在SELECT子句中使用。
  • 窗口函数OVER 中的ORDER BY 子句并不会影响最终结果的排序。其只是用来决定窗口函数按何种顺序计算。

GROUPING运算符

ROLLUP - 计算合计及小计

SELECT  product_type
       ,regist_date
       ,SUM(sale_price) AS sum_price
  FROM product
 GROUP BY product_type, regist_date WITH ROLLUP  

效果如下
在这里插入图片描述

练习题

1

请说出针对本章中使用的 product(商品)表执行如下 SELECT 语句所能得到的结果。

SELECT  product_id
       ,product_name
       ,sale_price
       ,MAX(sale_price) OVER (ORDER BY product_id) AS Current_max_price
  FROM product

答:Current_max_price列的值是该行及之前行的sale_price的最大值

+------------+--------------+------------+-------------------+
| product_id | product_name | sale_price | Current_max_price |
+------------+--------------+------------+-------------------+
| 0001       | T恤衫        |       1000 |              1000 |
| 0002       | 打孔器       |        500 |              1000 |
| 0003       | 运动T恤      |       4000 |              4000 |
| 0004       | 菜刀         |       3000 |              4000 |
| 0005       | 高压锅       |       6800 |              6800 |
| 0006       | 叉子         |        500 |              6800 |
| 0007       | 擦菜板       |        880 |              6800 |
| 0008       | 圆珠笔       |        100 |              6800 |
+------------+--------------+------------+-------------------+

2

继续使用product表,计算出按照登记日期(regist_date)升序进行排列的各日期的销售单价(sale_price)的总额。排序是需要将登记日期为NULL 的“运动 T 恤”记录排在第 1 位(也就是将其看作比其他日期都早)

答:
窗口函数: 发现日期没有合并,如果在 FROM product后加GROUP BY regist_date则加总失败

    SELECT  regist_date
       ,SUM(sale_price) OVER (PARTITION BY regist_date ORDER BY regist_date ASC) AS date_sum
  FROM product;
  +-------------+----------+
| regist_date | date_sum |
+-------------+----------+
| NULL        |     4000 |
| 2008-04-28  |      880 |
| 2009-01-15  |     6800 |
| 2009-09-11  |      500 |
| 2009-09-20  |     4500 |
| 2009-09-20  |     4500 |
| 2009-09-20  |     4500 |
| 2009-11-11  |      100 |
+-------------+----------+
8 rows in set (0.00 sec)

不使用窗口函数: 得到理想结果

SELECT  regist_date
       ,SUM(sale_price) AS date_sum
  FROM product
  GROUP BY regist_date
  ORDER BY regist_date ASC;
  +-------------+----------+
| regist_date | date_sum |
+-------------+----------+
| NULL        |     4000 |
| 2008-04-28  |      880 |
| 2009-01-15  |     6800 |
| 2009-09-11  |      500 |
| 2009-09-20  |     4500 |
| 2009-11-11  |      100 |
+-------------+----------+
6 rows in set (0.00 sec)

3 思考题

① 窗口函数不指定PARTITION BY的效果是什么?

答:窗口函数作用的对象以全体作为一类,如做售价排行,有PARTITION BY product_type的结果为

+--------------+--------------+------------+---------+
| 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 rows in set (0.00 sec)

而没有PARTITION BY product_type的结果为

+--------------+--------------+------------+---------+
| product_name | product_type | sale_price | ranking |
+--------------+--------------+------------+---------+
| 圆珠笔       | 办公用品     |        100 |       1 |
| 打孔器       | 办公用品     |        500 |       2 |
| 叉子         | 厨房用具     |        500 |       2 |
| 擦菜板       | 厨房用具     |        880 |       4 |
| T恤衫        | 衣服         |       1000 |       5 |
| 菜刀         | 厨房用具     |       3000 |       6 |
| 运动T恤      | 衣服         |       4000 |       7 |
| 高压锅       | 厨房用具     |       6800 |       8 |
+--------------+--------------+------------+---------+
8 rows in set (0.00 sec)

② 为什么说窗口函数只能在SELECT子句中使用?实际上,在ORDER BY 子句使用系统并不会报错。

答:
以上一题代码为例,在最后加入ORDER BY ranking,则效果如下:

mysql> SELECT product_name       ,product_type       ,sale_price       ,RANK() OVER (PARTITION BY product_type                         ORDER BY sale_price) AS ranking  FROM product
    -> ORDER BY ranking;
+--------------+--------------+------------+---------+
| product_name | product_type | sale_price | ranking |
+--------------+--------------+------------+---------+
| 圆珠笔       | 办公用品     |        100 |       1 |
| 叉子         | 厨房用具     |        500 |       1 |
| T恤衫        | 衣服         |       1000 |       1 |
| 打孔器       | 办公用品     |        500 |       2 |
| 擦菜板       | 厨房用具     |        880 |       2 |
| 运动T恤      | 衣服         |       4000 |       2 |
| 菜刀         | 厨房用具     |       3000 |       3 |
| 高压锅       | 厨房用具     |       6800 |       4 |
+--------------+--------------+------------+---------+
8 rows in set (0.00 sec)
mysql> SELECT product_name       ,product_type       ,sale_price       ,RANK() OVER (PARTITION BY product_type                         ORDER BY sale_price) AS ranking  FROM product
    -> ORDER BY sale_price;
+--------------+--------------+------------+---------+
| product_name | product_type | sale_price | ranking |
+--------------+--------------+------------+---------+
| 圆珠笔       | 办公用品     |        100 |       1 |
| 打孔器       | 办公用品     |        500 |       2 |
| 叉子         | 厨房用具     |        500 |       1 |
| 擦菜板       | 厨房用具     |        880 |       2 |
| T恤衫        | 衣服         |       1000 |       1 |
| 菜刀         | 厨房用具     |       3000 |       3 |
| 运动T恤      | 衣服         |       4000 |       2 |
| 高压锅       | 厨房用具     |       6800 |       4 |
+--------------+--------------+------------+---------+
8 rows in set (0.00 sec)

可以明显感受到再排序的实际意义并不大,反而还会使原来的分组显得混乱。当然在部分情况下有意义,如各班的前几名放在全年级的排名分别是什么样的分布情况

当只在ORDER BY语句中使用窗口函数时

mysql> SELECT product_name       ,product_type       ,sale_price   FROM product ORDER BY RANK() OVER (PARTITION BY product_type                         ORDER BY sale_price) ;
+--------------+--------------+------------+
| product_name | product_type | sale_price |
+--------------+--------------+------------+
| 圆珠笔       | 办公用品     |        100 |
| 叉子         | 厨房用具     |        500 |
| T恤衫        | 衣服         |       1000 |
| 打孔器       | 办公用品     |        500 |
| 擦菜板       | 厨房用具     |        880 |
| 运动T恤      | 衣服         |       4000 |
| 菜刀         | 厨房用具     |       3000 |
| 高压锅       | 厨房用具     |       6800 |
+--------------+--------------+------------+
8 rows in set (0.00 sec)

发现首先不能设定别名,其次不能单独开列表现出排序的依据,因此窗口函数一般都只在SELECT子句中使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQL高级的非过程化编程语言,是沟通数据库服务器和客户端的重要工具,允许用户在高层数据结构上工作。它不要求用户指定对数据的存放方法,也不需要用户了解具体的数据存放方式,所以,具有完全不同底层结构的不同数据库系统,可以使用相同的SQL语言作为数据输入与管理的SQL接口。 它以记录集合作为操作对象,所有SQL语句接受集合作为输入,返回集合作为输出,这种集合特性允许一条SQL语句的输出作为另一条SQL语句的输入,所以SQL语句可以嵌套,这使它具有极大的灵活性和强大的功能,在多数情况下,在其他语言中需要一大段程序实现的功能只需要一个SQL语句就可以达到目的,这也意味着用SQL语言可以写出非常复杂的语句。    结构化查询语言(Structured Query Language)最早是IBM的圣约瑟研究实验室为其关系数据库管理系统SYSTEM R开发的一种查询语言,它的前身是SQUARE语言。SQL语言结构简洁,功能强大,简单易学,所以自从IBM公司1981年推出以来,SQL语言得到了广泛的应用。如今无论是像Oracle、Sybase、DB2、Informix、SQL Server这些大型的数据库管理系统,还是像Visual Foxpro、PowerBuilder这些PC上常用的数据库开发系统,都支持SQL语言作为查询语言。    美国国家标准局(ANSI)与国际标准化组织(ISO)已经制定了SQL标准。ANSI是一个美国工业和商业集团组织,负责开发美国的商务和通讯标准。ANSI同时也是ISO和International Electrotechnical Commission(IEC)的成员之一。ANSI 发布与国际标准组织相应的美国标准。1992年,ISO和IEC发布了SQL国际标准,称为SQL-92。ANSI随之发布的相应标准是ANSI SQL-92。ANSI SQL-92有时被称为ANSI SQL。尽管不同的关系数据库使用的SQL版本有一些差异,但大多数都遵循 ANSI SQL 标准。SQL Server使用ANSI SQL-92的扩展集,称为T-SQL,其遵循ANSI制定的 SQL-92标准。    SQL语言包含4个部分:    数据定义语言(DDL),例如:CREATE、DROP、ALTER等语句。    数据操作语言(DML),例如:INSERT(插入)、UPDATE(修改)、DELETE(删除)语句。    数据查询语言(DQL),例如:SELECT语句。    数据控制语言(DCL),例如:GRANT、REVOKE、COMMIT、ROLLBACK等语句。    SQL语言包括三种主要程序设计语言类别的语句:数据定义语言(DDL),数据操作语言(DML)及数据控制语言(DCL)。
### 回答1: Python学习笔记|字符串与正则表达式练习题答案 1. 练习题1: 题目:给定一个字符串s,找出其中的连续的最长的数字串。 答案:可以通过正则表达式来匹配数字串,然后使用max函数找出最长的。 代码示例: import re def find_longest_num_str(s): num_str_list = re.findall('\d+', s) longest_str = max(num_str_list, key=len) return longest_str s = "ab1234c56789def" print(find_longest_num_str(s)) 输出:56789 2. 练习题2: 题目:给定一个字符串s,将其中的每个空格替换为"%20"。 答案:可以通过正则表达式的sub函数来实现替换。 代码示例: import re def replace_space(s): new_s = re.sub(' ', '%20', s) return new_s s = "Hello World" print(replace_space(s)) 输出:Hello%20World 3. 练习题3: 题目:给定一个字符串s,判断它是否为回文字符串。 答案:可以使用切片操作将字符串反转,然后与原字符串进行比较。 代码示例: def is_palindrome(s): return s == s[::-1] s = "abcba" print(is_palindrome(s)) 输出:True ### 回答2: 以下是关于字符串和正则表达式练习题的答案: 1. 给定一个字符串s,编写一个函数,返回该字符串的反转字符串。 def reverse_string(s): return s[::-1] 2. 给定一个字符串s,编写一个函数,返回是否是回文字符串。 def is_palindrome(s): return s == s[::-1] 3. 给定一个字符串s和一个字符c,编写一个函数,返回字符串s中字符c的出现次数。 def count_char(s, c): return s.count(c) 4. 给定一个字符串s,编写一个函数,返回字符串s中的所有单词列表。 def split_words(s): return s.split() 5. 给定一个字符串s,编写一个函数,返回字符串s中的所有数字列表。 import re def extract_numbers(s): return re.findall(r'\d+', s) 这只是一些可能的答案,其中的解决方法可以有很多种。每个问题都有不同的解决方案,具体取决于个人的编程风格和需求。希望这些答案能够帮助你理解和学习Python中的字符串和正则表达式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值