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

用ORACLE分析函数decode实现行列转换

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

概述

对数据库中的数据用SQL实现行列转换,不但需要编写复杂的程序代码,还需要编写存储过程。若引入ORACLE中的分析函数则会使该过程简便很多。首先找出表中所有关键字的属性个数的最大值,设为n,其次为每个关键字新添加n列,并用分析函数查询关键字的属性所处列的位置,然后将每个关键字的多行属性转换成多列属性,最后把生成的多个新列拼成一个串形成一列,从而实现行列转换。


引言

分析函数的设计目的是为了解决诸如“累计计算”等问题。虽然大部分的问题都可以用PL/SQL解决,但是性能并不理想,首先查询本身并不容易编写,其次有些很难在SQL中直接做的查询但实际上是很普通的操作,比如实现数据表中行列传换。这样的问题在SQL中做查询就很困难。在分析函数出现以前,我们必须使用自联查询或者子查询甚至复杂的存储过程实现的语句,现在只要一条简单的SQL语句就可以实现了,而且在执行效率方面也有相当大的提高。本文将以一个实例来描述如何采用分析函数实现数据中的行列互换。


原理

1、分析函数的格式及语法

分析函数是在一个记录行分组的基础上计算它们的总值。行的分组被称窗口,并通过分析语句定义。对于每记录行,定义了一个“滑动”窗口。该窗口确定“当前行”计算的范围。窗口的大小可由各行的实际编号或由时间等逻辑间隔确定。

分析函数以如下形式开头:

Analytic-Function(<Argument>,<Argument>,...)
OVER (<Query-Partition-Clause><Order-By-Clause><Windowing-Clause>)

(1)Analytic-Function:分析函数的名称,Oracle10gR2带的内置分析函数有多个,包括:AVG、CORR、COVAR_POP、COVAR_SAMP、COUNT、LAG、LAST、LEAD、MAX、MIN、RANK、SUM等;对于用户自定义的分析函数,分析函数名称需要满足标识符规则。

(2)Arguments:参数,分析函数通常有0到3个参数,参数可以是任何数字类型或是可以隐式转换为数字类型的数据类型。对于用户自定义的参数,可以根据实际情况使用。

(3)OVER:是分析函数就必须使用的关键字,对于既可作为聚集函数又可作为分析函数的函数,Oracle无法识别,必须用over来标识此函数为分析函数。

(4)Query-Partition-Clause:查询分组子句,根据划分表达式设置的规则,PARTITION BY将一个结果逻辑分成N个分组划分表达式。分析函数独立应用于各个分组,并在应用时重置。

(5)Order-By-Clause:(按…排序分组),是排序子句,根据一个或多个排序表达式对分组进行排序。

(6)Windowing-Clause窗口生成语句:窗口生成语句用以定义滑动或固定数据窗口,分析函数在分组内进行分析。该语句能够对分组中任意定义的滑动或固定窗口进行计算。

2、实例原理介绍

本实例是将具有相同关键字的多条记录中的某一不同列合并成一列,例如在一个临时表中包含有用户的编号、电话号码、产品名称、所在营业区以及相关业务名称5个字段,而每个用户的业务可能有多项,这样创建数据表将会造成冗余,现在要想办法将表中编号、电话号码、产品名称、所在营业区四个字段相同的用户的相关业务属性合并成一列解决冗余问题,使用SQL语句会比较困难,甚至需要一定的存储过程。使用Orcale中的分析函数来实现这样的行列转换就比较简单方便了。

3、实例

1)创建临时表

create table temp (
num varchar2(15),
name varchar2(20),
sex varchar2(2),
classes varchar2(30),
course_name varchar2(50) );

2)构造数据

insert into temp(num,name,sex,classes,course_name) values ('206211','王艺','男','06-1班','保险学');
insert into temp(num,name,sex,classes,course_name) values ('206212','肖薇','女','06-2','保险学');
insert into temp(num,name,sex,classes,course_name) values ('206212','肖薇','女','06-2','财务管理');
insert into temp(num,name,sex,classes,course_name) values ('206212','肖薇','女','06-2','财务会计');
insert into temp(num,name,sex,classes,course_name) values ('206213','陈雅诗','女','06-2','电子商务');
insert into temp(num,name,sex,classes,course_name) values ('206213','陈雅诗','女','06-2','公共经济学');
insert into temp(num,name,sex,classes,course_name) values ('206213','陈雅诗','女','06-2','公司理财');
insert into temp(num,name,sex,classes,course_name) values ('206213','陈雅诗','女','06-2','管理学原理');
insert into temp(num,name,sex,classes,course_name) values ('206213','陈雅诗','女','06-2','保险学');
insert into temp(num,name,sex,classes,course_name) values ('206214','李丹阳','男','06-1','保险学');
insert into temp(num,name,sex,classes,course_name) values ('206214','李丹阳','男','06-1','财务管理');
insert into temp(num,name,sex,classes,course_name) values ('206214','李丹阳','男','06-1','财务会计');
insert into temp(num,name,sex,classes,course_name) values ('206214','李丹阳','男','06-1','电子商务');
insert into temp(num,name,sex,classes,course_name) values ('206214','李丹阳','男','06-1','公共经济学');
insert into temp(num,name,sex,classes,course_name) values ('206215','杨伊琳','女','06-3班','环境管理学');
insert into temp(num,name,sex,classes,course_name) values ('206215','杨伊琳','女','06-3班','管理学原理');
insert into temp(num,name,sex,classes,course_name) values ('206215','杨伊琳','女','06-3班','商务谈判');
insert into temp(num,name,sex,classes,course_name) values ('206216','李佳琪','男','06-2','土地估计');
Commit;

3)先查一下course_name最多的组合

select max(count(course_name))
from temp
group by num,name,sex,classes;

4) 列的位置

用分析函数中的row_number函数,在num,name,sex,classes相同的情况下course_name所处的列的位置(第几列)。

row_number函数解释:返回有序组中一行的偏移量,从而可用于按特定标准排序的行号。

select num,
 name,
 sex,
 classes,
 course_name,
 row_number() over(partition by num, name, sex, classes order by course_name) rn
 from temp;

5)把course_name的所有的行换成列

select num,name,sex,classes,
 max(decode(rn,1,course_name,null)) course_name_1,
 max(decode(rn,2,course_name,null)) course_name_2,
 max(decode(rn,3,course_name,null)) course_name_3,
 max(decode(rn,4,course_name,null)) course_name_4,
 max(decode(rn,5,course_name,null)) course_name_5
from (select num,name,sex,classes,course_name,
row_number() over(partition by num,name,sex,classes order by course_name) rn
 from temp)
group by num,name,sex,classes;

6)把转换后的name拼成一个字符串,放在一行

select num,
 name,
 sex,
 classes,
 (max(decode(rn, 1, course_name, null)) ||
 max(decode(rn, 2, ',' || course_name, null)) ||
 max(decode(rn, 3, ',' || course_name, null)) ||
 max(decode(rn, 4, ',' || course_name, null)) ||
 max(decode(rn, 5, ',' || course_name, null))) name
 from (select num,
 name,
 sex,
 classes,
 course_name,
 row_number() over(partition by num, name, sex, classes order by course_name) rn
 from temp)
 group by num, name, sex, classes;

总结

本文中的程序能够实现以下功能:

①计算具有相同关键字的最多的组合;

②根据分析函数查询某一关键字所处的列的位置;

③把需合并列的所有的行换成列;

④把需要合并的某几列拼成一个串。

分析函数除了拥有以上所介绍的功能,还能够实现诸如求和、Top-N查询、统计某个范围的数据行窗口、交叉表查询等功能。

后面会分享更多关于sql怎么去优化的内容,感兴趣的朋友可以关注下~·

相关推荐

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系统中,设置路由通常是为了解决以下问题:该...

取消回复欢迎 发表评论: