所谓的数据稠化,就是补全缺失的数据。因为在数据库表中,存储的数据经常是稀疏的(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 实现数据稠化报表的更多相关文章

  1. Oracle数据稠化

                姓名                      学科                分数             城市                张三           ...

  2. Oracle Partition Outer Join 稠化报表

    partition outer join实现将稀疏数据转为稠密数据,举例: with t as (select deptno, job, sum(sal) sum_sal from emp group ...

  3. oracle 分组取第一行数据 ,查询sql语句

    oracle  分组取第一行数据 SELECT * FROM ( SELECT ROW_NUMBER() OVER(PARTITION BY x ORDER BY y DESC) rn, t.* FR ...

  4. Oracle、MySql、SQLServer数据分页查询

    看过此博文后Oracle.MySql.SQLServer 数据分页查询,在根据公司的RegionRes表格做出了 SQLserver的分页查询语句: 别名.字段 FROM( SELECT row_nu ...

  5. 查询oracle数据库,返回的数据是乱码。 PL/SQL正常。

    查询oracle数据库,返回的数据是乱码. PL/SQL正常. 解决方案如下:

  6. ORACLE使用EXPDP和IMPDP数据泵进行导出导入的方法

    ORACLE使用EXPDP和IMPDP数据泵进行导出导入的方法 (2010-05-28 12:54:34) http://blog.sina.com.cn/s/blog_67d41beb0100ixn ...

  7. Oracle查询表里的重复数据方法:

    一.背景 一张person表,有id和name的两个字段,id是唯一的不允许重复,id相同则认为是重复的记录. 二.解决 select id from group by id having count ...

  8. for循环往Oracle中插入n条数据,主键自增

    1.主键自增实现方法:http://www.cnblogs.com/Donnnnnn/p/5959871.html 2.for循环往Oracle中插入n条数据 BEGIN .. loop insert ...

  9. Oracle数据库的创建、数据导入导出

    如何结合Sql脚本和PL/SQL Developer工具来实现创建表空间.创建数据库.备份数据库.还原数据库等操作,然后实现Oracle对象创建.导入数据等操作,方便我们快速了解.创建所需要的部署Sq ...

随机推荐

  1. MockMVC

    随着RESTful Web Service的流行,测试对外的Service是否满足期望也变的必要的.从Spring 3.2开始Spring了Spring Web测试框架 Spring MVC测试框架提 ...

  2. spring 学习二 @RequestMapping

    RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上.用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径. RequestMapping注解有六个属性,下面我们把她 ...

  3. 配置docker中免密码SSH

    更换docker国内镜像,使用DaoCloud,特别快 编写Dockerfile文件 FROM ubuntu MAINTAINER ggzone xxx@live.com ENV REFRESHED_ ...

  4. 侯捷STL学习(八)-- 深度探索deque

    layout: post title: 侯捷STL学习(八) date: 2017-07-19 tag: 侯捷STL --- 第十八节 深度探索deque上 duque内存结构 分段连续,用户看起来是 ...

  5. java常用八大排序法

    最近查资料发现java排序挺有意思的,其中包含常见八种具有代表性的排序法:笔者觉得排序的功能重要,但更重要的是排序的思想:所以简单叙述一下常见排序方法名称,并用代码举例. A.插入排序(直接插入排序. ...

  6. C语言学习笔记--多维数组和多维指针

    1. 指向指针的指针 (1)指针的本质是变量,会占用一定的内存空间 (2)可以定义指针的指针来保存指针变量的地址值 (3)指针是个变量,同样也存在传值调用与传址调用 重置动态空间的大小 #includ ...

  7. sizeof总结

    1.sizeof常用总结 ①与strlen比较       strlen 计算字符串的字符数,以"\0"为结束判断,但不统计结束符.   sizeof 计算数据(数组.变量.类型. ...

  8. solr增量数据配置说明

    转帖地址:http://www.blogjava.net/conans/articles/379546.html 以下资料整理自网络,觉的有必要合并在一起,这样方便查看.主要分为两部分,第一部分是对& ...

  9. Codeforces 464E The Classic Problem (最短路 + 主席树 + hash)

    题意及思路 这个题加深了我对主席树的理解,是个好题.每次更新某个点的距离时,是以之前对这个点的插入操作形成的线段树为基础,在O(logn)的时间中造出了一颗新的线段树,相比直接创建n颗线段树更省时间. ...

  10. 线段树教做人系列(2)HDU 4867 XOR

    题意:给你一个数组a,长度为.有两种操作.一种是改变数组的某个元素的值,一种是满足某种条件的数组b有多少种.条件是:b[i] <= a[i],并且b[1]^b[2]...^b[n] = k的数组 ...