百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 优雅编程 > 正文

数据库:1 小时 SQL 极速入门(三)之分析函数

sinye56 2024-09-22 08:26 6 浏览 0 评论

今天我们讲一些在做报表和复杂计算时非常实用的分析函数。由于各个数据库函数的实现不太一样,本文基于 Oracle 12c 。

ROW_NUMBER()函数

这个函数在平时用的还是比较多的。这个函数的作用是为分组内的每一行返回一个行号。我们还是举例来说明。

假设我们有以下数据表:


共 8 个订单,分为 A,B,C,D四种类型,后面两列是订单描述和订单数量。

假如我们现在想找到每个订单类型中数量最少的一行记录,比如想找到 A 类型订单数量最少的,B 类型订单数量最少的。。。

我们要怎么写呢 ? 用 GROUP BY 可能会很麻烦。这里用 ROW_NUMBER() 就很合适

SELECT order_no,
 order_type,
 order_text,
 order_qty,
 row_number() OVER(PARTITION BY order_type order by order_qty) AS rowno
FROM wip_order_test

结果:


可以看到,每一行最后都有一个从低到高的编号,有了这个编号我们就可以通过取编号为 1 的行来得到每个分组中订单数量最少的一行记录。

解释一下,ROW_NUMBER() 为每一行返回一个行号, partition by 表示分组,这里表示根据 order_type 分组,然后我们按照订单数量排序。就会得到每个分组内的按照订单数量排序的行号。

SUM() OVER()函数

假如我们现在要 查询每个类型的订单总数分别是多少,要怎么做?

大家可能会想到 GROUP BY,不过大家可以自己试试,是否能得到和我同样的结果

SELECT order_no,
 order_type,
 order_text,
 order_qty,
 sum(order_qty) OVER(PARTITION BY order_type) AS sum_qty
FROM wip_order_test

结果:


看到后面多了一个数量列,就是每个分组的订单总数量。是不是很方便?

除了 SUM 函数,其他几个计算函数如 AVG(),MAX(),MIN(),COUNT()的使用方法和 SUM 一样。

窗口函数

窗口函数可以对一个结果集内的一定范围内值进行累积,或者通过移动窗口进行累积。还是看例子吧。

SELECT order_no,
 order_type,
 order_text,
 order_qty,
 sum(order_qty) OVER
 (ORDER BY order_no ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
 AS cumulative_qty
FROM wip_order_test;



解释一下:还是用 SUM 来计算总和,这里我们使用了新的语法, ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 定义了窗口的起点和终点,UNBOUNDED PRECEDING表示起点在第一行,CURRENT ROW 表示终点在当前行。我们看一下上图的结果,能看到最后一列的值是逐行累加的。

移动窗口

上面我们的窗口的起点是固定的,终点逐渐往下移,我们可以创建一个固定大小的窗口,起点和终点同时往下移动。只需要修改 UNBOUNDED 为一个固定的数字就可以了。我们修改成 2, 和 3 分别看一下

SELECT order_no,
 order_type,
 order_text,
 order_qty,
 SUM(order_qty) OVER (ORDER BY order_no ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS cumulative_qty2,
 SUM(order_qty) OVER (ORDER BY order_no ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) AS cumulative_qty3
FROM wip_order_test;



解释下:倒数第二列我们修改窗口起点2,表示当前行与前两行之间的范围。可以看到每一行的值都是当前行与它前面两行的值的累加。而最后一列,是当前行与它之前3行的值的累加。每处理一行,窗口的起点和终点都向下移动。

同理,SUM 也可以改为 AVG 求窗口的平均值

FIRST_VALUE() 和 LAST_VALUE()可以获取窗口的第一行和最后一行,NTH_VALUE()可以获取第 N 行。看一下例子:

SELECT order_no,
 order_type,
 order_text,
 order_qty,
 first_value(order_qty) OVER (ORDER BY order_no ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS first_value,
 last_value(order_qty) OVER (ORDER BY order_no ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) AS last_value,
 nth_value(order_qty,2) OVER (ORDER BY order_no ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) AS second_value
FROM wip_order_test;



LISTAGG() 函数

这个函数很有用,有时候在 GROUP BY 以后,我们想让分组内的某一列的几个值显示在一行上,比如:

SELECT 
 order_type,
 listagg(to_char(order_text),'-') WITHIN GROUP (ORDER BY order_type) AS text
FROM wip_order_test
GROUP BY order_type

结果:


看到,通过 LISTAGG ,把每个分组中的订单描述字段连接起来。第一个参数表示要合并的字段名字,第二个参数表示分隔符。

TOP-N 查询

Oracle 12c中新增了对 TOP-N的支持。

SELECT order_no,
 order_type,
 order_text,
 order_qty
FROM wip_order_test
FETCH FIRST 3 ROWS ONLY;



我们用 FETCH FIRST 3 取出了前 3 行数据,这里也可以使用 FETCH FIRST 20 PERCENT ROWS ONLY 用百分比来取出前 20% 的数据。

还可以使用 OFFSET 关键字,来表示从第几行开始取,比如 OFFSET 5 ROWS FETCH NEXT 3 ROWS ONLY 就表示从第 5 行开始往下取 3 行。

中位数 PERCENTILE_CONT()

可以算一组值的中位数,传入一个参数,比如传入0.5 表示 1/2 中位数,0.75 表示 3/4 中位数

SELECT order_type,
 percentile_cont(0.5) WITHIN GROUP (
ORDER BY order_qty) AS A,
 percentile_cont(0.75) WITHIN GROUP (
ORDER BY order_qty) AS b
FROM wip_order_test
GROUP BY order_type



我们根据订单类型分组后,分别算出每种订单类型数量的 1/2 中位数和 3/4中位数。

相关推荐

RHEL8和CentOS8怎么重启网络

本文主要讲解如何重启RHEL8或者CentOS8网络以及如何解决RHEL8和CentOS8系统的网络管理服务报错,当我们安装好RHEL8或者CentOS8,重启启动网络时,会出现以下报错:...

Linux 内、外网双网卡路由配置

1.路由信息的影响Linux系统中如果有多张网卡的情况下,如果路由信息配置不正确,...

Linux——centos7修改网卡名

修改网卡名这个操作可能平时用不太上,可作为了解。修改网卡默认名从ens33改成eth01.首先修改网卡配置文件名(建议将原配置文件进行备份)...

CentOS7下修改网卡名称为ethX的操作方法

?Linux操作系统的网卡设备的传统命名方式是eth0、eth1、eth2等,而CentOS7提供了不同的命名规则,默认是基于固件、拓扑、位置信息来分配。这样做的优点是命名全自动的、可预知的...

Linux 网卡名称enss33修改为eth0

一、CentOS修改/etc/sysconfig/grub文件(修改前先备份)为GRUB_CMDLINE_LINUX变量增加2个参数(net.ifnames=0biosdevname=0),修改完成...

CentOS下双网卡绑定,实现带宽飞速

方式一1.新建/etc/sysconfig/network-scripts/ifcfg-bond0文件DEVICE=bond0IPADDR=191.3.60.1NETMASK=255.255.2...

linux 双网卡双网段设置路由转发

背景网络情况linux双网卡:网卡A(ens3)和网卡B(...

Linux-VMware设置网卡保持激活

Linux系统只有在激活网卡的状态下才能去连接网络,进行网络通讯。修改配置文件(永久激活网卡)...

VMware虚拟机三种网络模式

01.VMware虚拟机三种网络模式由于linux目前很热门,越来越多的人在学习linux,但是买一台服务放家里来学习,实在是很浪费。那么如何解决这个问题?虚拟机软件是很好的选择,常用的虚拟机软件有v...

Rocky Linux 9/CentOS Stream 9修改网卡配置/自动修改主机名(实操)

推荐...

2023年最新版 linux克隆虚拟机 解决网卡uuid重复问题

问题描述1、克隆了虚拟机,两台虚拟机里面的ip以及网卡的uuid都是一样的2、ip好改,但是uuid如何改呢?解决问题1、每台主机应该保证网卡的UUID是唯一的,避免后面网络通信有问题...

Linux网卡的Vlan配置,你可能不了解的玩法

如果服务器上连的交换机端口已经预先设置了TRUNK,并允许特定的VLAN可以通过,那么服务器的网卡在配置时就必须指定所属的VLAN,否则就不通了,这种情形在虚拟化部署时较常见。例如在一个办公环境中,办...

Centos7 网卡绑定

1、切换到指定目录#备份网卡数据cd/etc/sysconfig/network-scriptscpifcfg-enp5s0f0ifcfg-enp5s0f0.bak...

Linux搭建nginx+keepalived 高可用(主备+双主模式)

一:keepalived简介反向代理及负载均衡参考:...

Linux下Route 路由指令使用详解

linuxroute命令用于显示和操作IP路由表。要实现两个不同子网之间的通信,需要一台连接两个网络的路由器,或者同时位于两个网络的网关来实现。在Linux系统中,设置路由通常是为了解决以下问题:该...

取消回复欢迎 发表评论: