热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

对于缓慢变化维的历史数据的处理

在做数据仓库的时候有一个备件维度,该维度由两张表构成。一张是R5PARTS这张表记录的是备件维度的当前状况。R5PARTS备件编码备件分类创建时间修改时间修改次数HCSD0370S

在做数据仓库的时候有一个备件维度,该维度由两张表构成。

一张是R5PARTS这张表记录的是备件维度的当前状况。

R5PARTS
备件编码备件分类创建时间修改时间修改次数
HCSD0370STOP2011/11/12 00:00:00 0

另外一张表记录的是备件所属分类的变化情况,R5AUDVALUES:

R5AUDVALUES

备件编码

变化之前的备件分类变化之后的备件分类变化日期
HCSD0370JDSTOP2013/11/11 00:00:00

这个维度是变化的,R5PARTS记录维度的当前状况,开始我们项目组没有考虑到维度变化的情况,直接用R5PARTS这张表来构建维度。后来发现维度会存在变化的情况,只用维度的当前情况不能完全反映维度和事实表的真实情况,比如在2013年公司发生了一笔采购,采购了HCSD0370这个备件,在当时这个备件的分类可能是属于机电(JD),后来这个物资被停用了,它现在物资分类是停用物资了(分类代码:STOP)。这时候(2014年)我们如果用现在的维度情况去看,就是在2013年公司采购了分类为停用物资(stop)的备件HCSD0370。而停用物资一般是不会去采购的,只会从现有的库存里面发放和消耗。这时就需要结合维度的变化情况来构建一个变化维。

        根据我们从网上收集的资料,和用户沟通之后,决定采用处理缓慢变化维的TYPE2(保留所有的维度变化情况)。

        我们用的ETL工具是informatica powercenter,在powercenter中有缓慢变化维抽取的wizard,但是我试了之后发现不能很好地满足我们的需求(不过思想是典型的缓慢变化维的处理方式,只是太过死板,每个项目的要求不一样),最终决定分成两个部分来做。

        我们根据缓慢变化维的TYPE2处理方法,重新设计了该备件维度的维度表:

SCD_DIM_PART

ORDMATERIAL_CODESTART_DATEEND_DATEIN_USE
1HCSD03702011/11/112013/11/110
2HCSD03702013/11/119999/1/1

1

       ORD表示维度的序号,MATERIAL_CODE是备件编码,START_DATE是这个备件编码和分类使用的开始日期,END_DATE是这个分类使用的终止日期,IN_USE表示的是当前是否在用这个备件分类。

       要构建这个缓慢变化维度,我们准备从两个方面入手,一是对于R5PARTS中那些没有被修改过的分类,直接抽取到SCD_DIM_PART。

SELECT
1 AS ORD,
备件编码 AS MATERIAL_CODE,
创建时间 AS START_DATE,
TO_DATE('9999/01/01','YYYY/MM/DD') AS END_DATE,
1 as IN_USE
FROM R5PARTS

WHERE UPDATECOUNT=0

        对于那些有分类变化的数据,我们直接根据变化表R5AUDVALUES这张表来构建。

        首先我们从R5AUDVALUES这张表找出所有有变化的备件编码,然后对每一个备件编码,分别查出它根据时间的排序,然后将这些数据插入到SCD_DIM_PART。

      对备件分类变化的处理SQL:

  

FOR MATERIAL_CODE IN (SELECT DISTINCT AUD.AVA_PRIMARYID FROM R5AUDVALUES AUD)--从R5AUDVALUES把存在变化的不重复的备件编码取出来,然后依次开始循环
LOOP--从备件编码的集合开始循环
INSERT INTO SCD_DIM_MATERIAL--把循环中的每一个编码相关的数据插入到SCD_DIM_MATERIAL表中
with T as
(SELECT RANK() OVER(ORDER BY AUDV.AVA_CHANGED) IN_ORDER,
AUDV.AVA_PRIMARYID MATERIAL_CODE,
AUDV.AVA_FROM CHANGED_FROM,
AUDV.AVA_TO CHANGED_TO,
AUDV.AVA_CHANGED CHANGED_DATE
FROM R5AUDVALUES AUDV
WHERE audv.ava_primaryid = MATERIAL_CODE.AVA_PRIMARYID),--这个是为了每次循环的时候动态地根据备件编码取出R5AUDVALUES的变化数据
T1 as (SELECT MAX(T.IN_ORDER) AS MAX_ORD FROM T)--取出该备件的最大变化行数
SELECT T.IN_ORDER,
T.MATERIAL_CODE,
T.CHANGED_FROM CLASS_CODE,
(case
when T.IN_ORDER = '1' THEN--如果是第一行,说明该变化的START_DATE要到R5PARTS表去找
(SELECT to_date(PAR.PAR_CREATED,'mm/dd/yyyy hh24:mi:ss')
FROM R5PARTS PAR
WHERE PAR.PAR_CODE = T.MATERIAL_CODE
AND ROWNUM <2)
ELSE--不是第一行的时候就取上一行的变化时间
(SELECT to_date(TT.CHANGED_DATE,'mm/dd/yyyy hh24:mi:ss')
FROM T TT
WHERE TT.IN_ORDER = T.IN_ORDER - 1)
END) START_DATE,
to_date(T.CHANGED_DATE,'mm/dd/yyyy hh24:mi:ss') AS END_DATE,--状态的截止时间就是这一行的变化时间
0 as in_use--这个状态现在不在使用中
FROM T
union all--上句SQL其实是把所有旧状态取出来,这句SQL是为了取出最新的备件分类
select
t.in_order+1,--比原来的最大行号大一
t.material_code,
t.changed_to,--这里取的是R5AUDVALUES.AVA_CHANGEDTO表示有分类变化的备件的最新状态
to_date(t.changed_date,'mm/dd/yyyy hh24:mi:ss') as start_date,--取这一行的变化时间作为最新分类的开始时间
to_date('9999/01/01 00:00:00','yyyy/mm/dd hh24:mi:ss') as end_date,--最新状态的停止时间设置为最大
1 as in_use --1表示这个状态是当前状态
from t
where t.in_order= (select T1.MAX_ORD from T1);--取编号最大的那行,若只有1也就取1
END LOOP;

        

           在构建好了维度表之后,事实表的数据需要做相应的修改(在ETL的时候根据时间判断该用哪个维度字段,用备件编码和序号做联合主键),之后就可以做OLAP和BI展现了。

          这样做的一个比较明显的缺点是每次都需要把表truncate之后再重新插入,其实也可以做增量,只是觉得增量做起来比较麻烦,而且维度表本身不会很大,所以就先这样了,希望能找到更好的解决办法。



推荐阅读
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • 本文介绍了Oracle存储过程的基本语法和写法示例,同时还介绍了已命名的系统异常的产生原因。 ... [详细]
  • 合并列值-合并为一列问题需求:createtabletab(Aint,Bint,Cint)inserttabselect1,2,3unionallsel ... [详细]
  • 本文介绍了如何在MySQL中将零值替换为先前的非零值的方法,包括使用内联查询和更新查询。同时还提供了选择正确值的方法。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文讨论了在数据库打开和关闭状态下,重新命名或移动数据文件和日志文件的情况。针对性能和维护原因,需要将数据库文件移动到不同的磁盘上或重新分配到新的磁盘上的情况,以及在操作系统级别移动或重命名数据文件但未在数据库层进行重命名导致报错的情况。通过三个方面进行讨论。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • Java学习笔记之使用反射+泛型构建通用DAO
    本文介绍了使用反射和泛型构建通用DAO的方法,通过减少代码冗余度来提高开发效率。通过示例说明了如何使用反射和泛型来实现对不同表的相同操作,从而避免重复编写相似的代码。该方法可以在Java学习中起到较大的帮助作用。 ... [详细]
author-avatar
双子座-海_358
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有