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 ...
随机推荐
- Druid 0.2.25版本hive jdbc 不支持 conn.getHoldability() 兼容处理问题
背景: 用Druid做Oracle的连接池感觉还不错,近日新项目要用Hive,故而也想使用Duid来做Hive的连接池.试了试果真可以,也没报错.但是,过了一段时间,同样的代码却出问题了.离奇的是我同 ...
- mongodb与mongodb可视化工具adminMongo结合使用
一,MongoDB的安置及配置 1,从MongoDB官网下载安装 https://www.mongodb.com/download-center#community 根据的电脑选择合适的版本安装: 根 ...
- -bash : ** : command not found的问题解决(图文详解)
问题来源 我不小心,配置错了,少了个export和PATH没配对. source /etc/profile 之前一定要留心,否则出错让你后悔去! 问题导致现象1 问题导致现象2 解决办法 按e键, ...
- import configparser
- 数据库理论-范式(1NF、2NF、3NF)
范式是“符合某一种级别的关系模式的集合,表示一个关系内部各属性之间的联系的合理化程度”. 第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项.(每个属性不可分割)第二范式(2NF)要求数据 ...
- Tensorflow手写数字识别训练(梯度下降法)
# coding: utf-8 import tensorflow as tffrom tensorflow.examples.tutorials.mnist import input_data #p ...
- Excel VBA连接MySql 数据库获取数据
编写Excel VBA工具,连接并操作Mysql 数据库. 系统环境: OS:Win7 64位 英文版 Office 2010 32位 英文版 1.VBA连接MySql前的准备 Tools---> ...
- C++中的纯虚函数和虚函数的作用
1. 虚函数和纯虚函数可以定义在同一个类(class)中,含有纯虚函数的类被称为抽象类(abstract class),而只含有虚函数的类(class)不能被称为抽象类(abstract class) ...
- 95E Lucky Country
传送门 题目大意 如果一个数中不包含除4和7之外的数字则是幸运数.有n个岛屿,通过双向道路连接.这些岛屿被分为几个地区.每个岛属于恰好一个区域,同一区域中的任何两个岛之间存在道路,不同区域的任何两个岛 ...
- Entity Framework Tutorial Basics(37):Lazy Loading
Lazy Loading: One of the important functions of Entity Framework is lazy loading. Lazy loading means ...