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 ...
随机推荐
- 删除pool error的解决方法
标签(空格分隔): ceph,ceph运维,pool 问题描述: 删除pool的时候提示下面的错误: [root@node3 ~]# ceph osd pool delete ecpool ecpoo ...
- urllib2模块中文翻译与学习 - Python 2.7.8官方文档
总结 目的 打开指定网址 要求 了解需要处理的网站的操作流程 数据包的构造与提交 对可能的响应处理选择合适的处理器(模块内的各种 *Handler()) 核心 urllib.urlencode(que ...
- SpringMVC---依赖注入与面向切面
1.依赖注入与面向切面 1.1.出现背景 ——如何简化java开发? 其中很重要的一点是“组件化”. ——如何更好的“组件化”? 松耦合,以及尽可能的让组件专注于本身. ——Spring框架的目的也只 ...
- 1107SQLserver基础--语句、存储过程
[随堂练习]--查询‘李数’老师教的数学成绩大于80分的学生的信息, 并且人数大于3的话,输出达标:否则输出不达标. 存储过程 --带参数的程序代码块---代表执行命令存储在数据库中,存储代码,没有调 ...
- UML在软件开发中各个阶段的作用和意义
经典的软件工程思想将软件开发分成5个阶段:需求分析,系统分析与设计,系统实现,测试及维护五个阶段. 之所以如此,是因为软件开发中饣含了物和人的因素,存在着很大的不确定性,这使得软件工程不可能像理想的, ...
- C语言学习笔记--内存分区
1. 程序中的栈 1.1 栈的简介 (1)栈中现代计算机程序里最为重要的概念之一 (2)栈在程序中用于维护函数调用上下文 (3)函数中的参数和局部变量存储在栈上 (4)栈保存了一个函数调用所需的维护信 ...
- spirng boot web配置开发
spring-booter-starter-web是spring-boot web发开的核心,自动配置信息存储在spring-boot-autoconfigure.jar 下面的web目录里面,包含了 ...
- PHP数组函数的使用
1.array_walk($arr, $func, [$data]) 使用用户自定义的函数遍历所有的元素,返回true/false $func是一个函数名 默认会传入两个参数 第一个 $arr的值, ...
- Swing界面组件的通用属性
----------------siwuxie095 Swing 界面组件(控件)的通用属性: (1)enabled:启用/禁用 ...
- Apollo问题
1.安装问题: 一不小心安装了NVIDIA,导致bash docker/scripts/dev_start.sh无法启动:[ERROR] Failed to start docker containe ...