Oracle使用PARTITION BY 实现数据稠化报表
所谓的数据稠化,就是补全缺失的数据。因为在数据库表中,存储的数据经常是稀疏的(sparse data),也就是不完整的。比如记录一个员工每个月的销售额,用这么一个销售表来记录:SalesRecord(Name(姓名),Date(日期),Sales(销售额)),假设某个月这个员工请假没上班,对应的没有销售额,一般也不会将这个员工的销售额存储为0,而是直接不存储,这样在销售表中就会产生缺失的行,导致的结果就是这些销售数据在时间上是不连续的,或者说就是缺失的。为了后续的一些统计,需要对数据进行补全也就是所谓的数据稠化。
下面做一个简单的例子,
图 1

需要知道每个人每科的成绩,这里就是需要补全数据,比如(Lucy的Chinese成绩??),因此,最终我们需要的到
的结果是这样的(红色背景是补全的内容):
图 2

步骤如下:
先创建一张成绩表Scores
--创建Scores表
create table Scores(
stuName varchar2(10),
subject varchar2(10),
score number );
然后插入数据,得到图1.
接下来,我们是实现一维(学科)数据稠密,也就是对学科,每个人都有每个学科,首先想到的是要找出所有学科(暂且这么做,以后经常是对另外一张学科表join),
废话少说,找出所有学科:
select distinct subject from Scores;

我们可以根据原表利用partition by()语法来进行下一步操作
--一维稠密数据
SELECT scores.stuname,
m.subject,
NVL(scores.score,0)
FROM scores
PARTITION BY (scores.stuname) --这里是重点
right join
(SELECT DISTINCT subject FROM scores) m
ON scores.subject=m.subject;
最终得到结果:

显然,上面的代码看起来很杂乱,我们可以来个with as 语法,使代码看起来清晰:
with
v1 as (select distinct subject from scores),
SELECT scores.stuname,v1.subject,NVL(scores.score,0) FROM scores
PARTITION BY (scores.stuname)
right join v1
ON scores.subject=v1.subject;
实现了一维的数据稠密,那么给表再添加个字段—年份,需要知道每个人,每年的每科成绩又怎么稠密呢?同样的道理
先实现一维的稠化,再在稠化后的基础上再稠化一次,以此类推就可以了嘛!
with
v1 as (select * from scores), --这是原表
v2 as (select distinct subject from scores), --所有科目
v3 as (select distinct dateyear from scores), --所有年份
v4 as (select v1.stuname,v2.subject,v1.score,v1.dateyear from v1
partition by (v1.stuname)
right join v2
on v1.subject = v2.subject) --v4就是对学科稠密化后的表,如图2所示
select v4.stuname , v4.subject , NVL(v4.score,0),v3.dateyear from v4
partition by (stuname,subject) --注意这里
right join v3 --最后在对v4进行年份的稠密,
on v4.dateyear=v3.dateyear;
这样就大功告成啦,每个人,每年的每课成绩均可有了。接下来,需要对着表进行行列转换如下图所示,这里我们以后再说!

下面实现二维数据稠化,我们同样有如下表:
| YEARMONTH | STUDENT | SUBJECT | SCORE |
| 201601 | Jim | Chinese | 78 |
| 201601 | Jim | Math | 34 |
| 201603 | Jim | English | 89 |
| 201605 | Jim | Physics | 88 |
| 201608 | Jim | Math | 67 |
| 201601 | Joe | Math | 87 |
| 201602 | Joe | Chinese | 87 |
| 201604 | Joe | Chinese | 55 |
| 201609 | Joe | Math | 45 |
| 201609 | Joe | Physics | 90 |
| YEARMONTH | STUDENT | SUBJECT | SCORE |
| 201601 | Jim | Chinese | 78 |
| 201601 | Jim | Math | 34 |
| 201601 | Jim | English | 0 |
| 201601 | Jim | Physics | 0 |
| 201602 | Jim | Chinese | 0 |
| 201602 | Jim | Math | 0 |
| 201602 | Jim | English | 0 |
| 201602 | Jim | Physic | 0 |
| 201603 | Jim | Chinese | 0 |
| 201603 | Jim | Math | 0 |
| 201603 | Jim | English | 89 |
| 201603 | Jim | Physics | 0 |

如右表所示,部分补全数据为红色背景的数据,其分数默认为0,这样我们就能看到
每个人(student维度)在所有时间(yearmonth维度)的每科(subject维度)的分数(score度量)
我们的做法应该是怎么样呢?
我们先做前期的准备,创建一张成绩表,并插入相应的数据
--创建学生成绩表
CREATE TABLE stu_score (
yearmonth number,
student VARCHAR2(20),
subject varchar2(20),
score number
)
--往表中插入数据
INSERT INTO stu_score VALUES(201601,'Jim','Chinese',78);
INSERT INTO stu_score VALUES(201601,'Jim','Math',34);
INSERT INTO stu_score VALUES(201603,'Jim','English',89);
INSERT INTO stu_score VALUES(201605,'Jim','Physics',88);
INSERT INTO stu_score VALUES(201608,'Jim','Math',67);
INSERT INTO stu_score VALUES(201601,'Joe','Math',87);
INSERT INTO stu_score VALUES(201602,'Joe','Chinese',87);
INSERT INTO stu_score VALUES(201604,'Joe','Chinese',55);
INSERT INTO stu_score VALUES(201609,'Joe','Math',45);
INSERT INTO stu_score VALUES(201609,'Joe','Physics',90);
同样,创建一张时间维度表
--创建时间维度表
CREATE TABLE DIM_DATE (
yearmonth number
);
INSERT INTO DIM_DATE VALUES(201601);
INSERT INTO DIM_DATE VALUES(201602);
INSERT INTO DIM_DATE VALUES(201603);
INSERT INTO DIM_DATE VALUES(201604);
INSERT INTO DIM_DATE VALUES(201605);
INSERT INTO DIM_DATE VALUES(201606);
INSERT INTO DIM_DATE VALUES(201607);
INSERT INTO DIM_DATE VALUES(201608);
INSERT INTO DIM_DATE VALUES(201609);
INSERT INTO DIM_DATE VALUES(201610);
INSERT INTO DIM_DATE VALUES(201611);
INSERT INTO DIM_DATE VALUES(201612);
然后,我们需要做的就是去稠化这些数据,保证在每个维度都有数据
WITH sub AS (
SELECT DISTINCT subject FROM stu_score
),
t1 as(
SELECT t.yearmonth,t.student,sub.subject,t.score FROM stu_score t
PARTITION BY (t.student) RIGHT JOIN sub
ON t.subject=sub.subject)
SELECT dim_date.yearmonth,t1.student,t1.subject,nvl(t1.score,0) FROM t1
PARTITION BY (student,subject)
right JOIN DIM_DATE ON dim_date.yearmonth = t1.yearmonth;
或者,不用创建临时表,直接合并
WITH sub AS ( --学科维度表,将所有学科选出
SELECT DISTINCT subject FROM stu_score
),
SELECT dim_date.yearmonth,t1.student,t1.subject,nvl(t1.score,0) FROM
(SELECT t.yearmonth,t.student,sub.subject,t.score FROM stu_score t
PARTITION BY (t.student) RIGHT JOIN sub
ON t.subject=sub.subject)t1 --对学科稠化,每个人在每个学科都有数据
PARTITION BY (student,subject)
right JOIN DIM_DATE ON dim_date.yearmonth = t1.yearmonth; --对日期稠化,保证每个日期都有数据
Oracle使用PARTITION BY 实现数据稠化报表的更多相关文章
- Oracle数据稠化
姓名 学科 分数 城市 张三 ...
- Oracle Partition Outer Join 稠化报表
partition outer join实现将稀疏数据转为稠密数据,举例: with t as (select deptno, job, sum(sal) sum_sal from emp group ...
- oracle 分组取第一行数据 ,查询sql语句
oracle 分组取第一行数据 SELECT * FROM ( SELECT ROW_NUMBER() OVER(PARTITION BY x ORDER BY y DESC) rn, t.* FR ...
- Oracle、MySql、SQLServer数据分页查询
看过此博文后Oracle.MySql.SQLServer 数据分页查询,在根据公司的RegionRes表格做出了 SQLserver的分页查询语句: 别名.字段 FROM( SELECT row_nu ...
- 查询oracle数据库,返回的数据是乱码。 PL/SQL正常。
查询oracle数据库,返回的数据是乱码. PL/SQL正常. 解决方案如下:
- ORACLE使用EXPDP和IMPDP数据泵进行导出导入的方法
ORACLE使用EXPDP和IMPDP数据泵进行导出导入的方法 (2010-05-28 12:54:34) http://blog.sina.com.cn/s/blog_67d41beb0100ixn ...
- Oracle查询表里的重复数据方法:
一.背景 一张person表,有id和name的两个字段,id是唯一的不允许重复,id相同则认为是重复的记录. 二.解决 select id from group by id having count ...
- for循环往Oracle中插入n条数据,主键自增
1.主键自增实现方法:http://www.cnblogs.com/Donnnnnn/p/5959871.html 2.for循环往Oracle中插入n条数据 BEGIN .. loop insert ...
- Oracle数据库的创建、数据导入导出
如何结合Sql脚本和PL/SQL Developer工具来实现创建表空间.创建数据库.备份数据库.还原数据库等操作,然后实现Oracle对象创建.导入数据等操作,方便我们快速了解.创建所需要的部署Sq ...
随机推荐
- RabbitMQ 四种Exchange
AMQP协议中的核心思想就是生产者和消费者隔离,生产者从不直接将消息发送给队列.生产者通常不知道是否一个消息会被发送到队列中,只是将消息发送到一个交换机.先由Exchange来接收,然后Exchang ...
- c# linq查询语句详细使用介绍
本文介绍Linq的使用方法 linq介绍 LINQ只不过是实现IEnumerable和IQueryable接口的类的扩展方法的集合. LINQ可以查询IEnumerable集合或者IQueryable ...
- spring整合mybatis的事物管理配置
一.基本配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http:/ ...
- ARQ
自动重传请求(Automatic Repeat-reQuest,ARQ)是OSI模型中数据链路层和传输层的错误纠正协议之一.它通过使用确认和超时这两个机制,在不可靠服务的基础上实现可靠的信息传输.如果 ...
- android 获取sharedpreference的三种方法的区别
1. public SharedPreferences getPreferences (int mode) 通过Activity对象获取,获取的是本Activity私有的Preference,保存在系 ...
- WebView三个方法区别(解决乱码问题)
最近使用WebView加载中文网页的时候出现乱码问题,网上整理下基本解决方法: 其实我发现这不管是在线还是离线显示都可以使用LoadUrl方法!联网时好像是默认utf-8,离线读取本地时需要设置默认编 ...
- [poj2318]TOYS(直线与点的位置关系)
解题关键:计算几何入门题,通过叉积判断. 两个向量的关系: P*Q>0,Q在P的逆时针方向: P*Q<0,Q在P的顺时针方向: P*Q==0,Q与P共线. 实际就是用右手定则判断的. #i ...
- webService(简单小demo)
1.什么是webService? 1.1.先说好处: WebService是两个系统的远程调用,使两个系统进行数据交互,如应用: 天气预报服务.银行ATM取款.使用邮箱账号登录各网站等. WebSer ...
- 2018网络预选赛 青岛 H
题目链接:https://pintia.cn/problem-sets/1036903825309761536/problems/1041156323504345088 题意:小明从某一点出发,向右方 ...
- MyBatis配置Setting详细说明
该表格转载自http://blog.csdn.net/summer_yuxia/article/details/53169227 setting是指定MyBatis的一些全局配置属性,这是MyBati ...