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 ...
随机推荐
- MongoDB 3.4 高可用集群搭建(二)replica set 副本集
转自:http://www.lanceyan.com/tech/mongodb/mongodb_repset1.html 在上一篇文章<MongoDB 3.4 高可用集群搭建(一):主从模式&g ...
- DCloud-5+Runtime:杂项
ylbtech-DCloud-5+Runtime:杂项 1.返回顶部 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 6.返回顶部 7.返回顶部 8.返回顶部 ...
- 微信小程序基础语法总结
本文介绍微信小程序语法 配置文件 app.json的配置(全局) { // 用来配置页面的路径 "pages":[ "pages/index/index", / ...
- 新增线下、APP、公众号多处入口,小程序会再火起来么?
现在,大多数互联网创业者最缺的是流量,第二缺的是钱.之前开发者们追捧小程序的重要原因就是在于认为这可能是下一个微信公众号体量的流量入口,因为大家都想从微信的8亿多用户中收获自己的一部分用户. 近期部分 ...
- 部署和调优 2.5 tomcat配置和优化
配置文件 vim /usr/local/tomcat/conf/server.xml 修改 <Connector port=" protocol="HTTP/1.1" ...
- 多媒体基础知识之YUV数据
1.什么是YUV格式 YUV,是一种颜色编码方法.Y表示明亮度(Luminance.Luma),也就是灰度值.U和V则是色度.浓度(Chrominance.Chroma),作用是描述影像色彩及饱和度, ...
- Ubuntu安装Chrome及hosts修改
Ubuntu16.04 1.chrome安装 获取安装包http://www.google.cn/chrome/browser/desktop/index.html 在安装包目录打开终端执行sudo ...
- spring 的aop操作
- css知多少(1)——我来问你来答(转)
css知多少(1)——我来问你来答 1. 引言 各位前端或者伪前端(比如作者本人)的同志们,css对你们来说不是很陌生.比如我,在几年之前上大学的时候,给外面做网站就用css,而且必须用css.这 ...
- node Util 模块
该util模块主要设计用于支持Node.js自己的内部API的需求.但是,许多实用程序对于应用程序和模块开发人员也很有用.它可以通过以下方式访问: const util = require('util ...