• 数据仓库开发之路之三时间维度的创建


    在数据仓库中,无一例外地需要和时间维度打交道,因此设计合理的时间维度,也是一个数据仓库项目开始必备的资源储备,如果有这方面的积累,就不用到处寻找合适的设计模型以及存储过程的代码了,否则可能需要花费一定的时间去寻找符合该项目合适的存储过程,或者自己动手编写。

    一般来说,时间维度的创建要根据实际的数据仓库应用来,基本上可以分为天、月的时间维度表,更细的可以分为半小时时间段,小时时间段等等,一般数据量大的时间维度都是利用存储过程来生成的。

    下面介绍一些时间维度表的设计结构。 

    <1>  时间维度表1(两列都是字段)
    维度属性
    维度属性
    日期关键字
    日历年月
    日期完全描述
    日历季度
    星期
    日历半年度
    纪元日编号
    日历年
    纪元周编号
    财政周
    纪元月编号
    年度财政周数
    日历日期编号
    财政月
    日历周编号
    年度财政月数
    日历月编号
    财政年月
    财政月日编号
    财政季度
    财政周编号
    财政季年度
    财政月编号
    财政半年度
    周末指示符
    财政年
    月末指示符
    节假日指示符
    日历周结束日期
    星期指示符
    年度日历周数
    销售时令
    日历月名
    重大事件
    年度日历月数
    其它
    <1>  时间维度表2
    a.日期维度

    名称

    代码

    数据类型

    主外键

    序列号

    C_ID

    int

    P

    日期

    C_DATE

    datetime

     

    星期

    C_WEEK

    varchar(12)

     

    月份

    C_MONTH

    varchar(2)

     

    C_YEAR

    varchar(4)

     

    季度

    C_QUARTER

    varchar(4)

     

    b.半小时时间维度
    

    名称

    代码

    数据类型

    主外键

    序列号

    C_ID

    Varchar(50)

     

    时段

    C_SHIDUAN

    Varchar(4000)

     

    c.时间段维度

    名称

    代码

    数据类型

    主外键

    序列号

    C_ID

    int

    P

    时间段

    C_Section

    varchar(50)

     

    开始时间

    C_Begin

    varchar(50)

     

    结束时间

    C_End

    varchar(50)

     

    3、比较完整的时间维度设计

    Name

    Type

    Nullable

    Comments

    DAY_CODE

    VARCHAR2(8)

    N

    日代码

    DAY_LONG_DESC

    VARCHAR2(30)

    N

    日完整名称

    DAY_MEDIUM_DESC

    VARCHAR2(30)

    N

    日中等长度名

    DAY_SHORT_DESC

    VARCHAR2(30)

    N

    日短名

    WEEK_CODE

    VARCHAR2(8)

    N

    周代码

    WEEK_LONG_DESC

    VARCHAR2(30)

    N

    周完整名称

    WEEK_MEDIUM_DESC

    VARCHAR2(30)

    N

    周中等长度名

    WEEK_SHORT_DESC

    VARCHAR2(30)

    N

    周短名

    TEN_DAY_CODE

    VARCHAR2(8)

    N

    旬代码

    TEN_DAY_LONG_DESC

    VARCHAR2(30)

    N

    旬完整名称

    TEN_DAY_MEDIUM_DESC

    VARCHAR2(30)

    N

    旬中等长度名

    TEN_DAY_SHORT_DESC

    VARCHAR2(30)

    N

    旬短名

    MONTH_CODE

    VARCHAR2(8)

    N

    月代码

    MONTH_LONG_DESC

    VARCHAR2(30)

    N

    月完整名称

    MONTH_MEDIUM_DESC

    VARCHAR2(30)

    N

    月中等长度名

    MONTH_SHORT_DESC

    VARCHAR2(30)

    N

    月短名

    QUARTER_CODE

    VARCHAR2(8)

    N

    季代码

    QUARTER_LONG_DESC

    VARCHAR2(30)

    N

    季完整名称

    QUARTER_MEDIUM_DESC

    VARCHAR2(30)

    N

    季中等长度名

    QUARTER_SHORT_DESC

    VARCHAR2(30)

    N

    季短名

    HALF_YEAR_CODE

    VARCHAR2(8)

    N

    半年代码

    HALF_LONG_DESC

    VARCHAR2(30)

    N

    半年完整名称

    HALF_MEDIUM_DESC

    VARCHAR2(30)

    N

    半年中等长度名

    HALF_SHORT_DESC

    VARCHAR2(30)

    N

    半年短名

    YEAR_CODE

    VARCHAR2(8)

    N

    年代码

    YEAR_LONG_DESC

    VARCHAR2(30)

    N

    年完整名称

    YEAR_MEDIUM_DESC

    VARCHAR2(30)

    N

    年中等长度名

    YEAR_SHORT_DESC

    VARCHAR2(30)

    N

    年短名

    ALL_TIME_CODE

    VARCHAR2(8)

    N

    全部时间代码

    ALL_TIME_DESC

    VARCHAR2(30)

    N

    全部时间名称

    DAY_TIMESPAN

    NUMBER(3)

    N

    日时间跨天

    DAY_END_DATE

    VARCHAR2(8)

    N

    结束日期

    WEEK_TIMESPAN

    NUMBER(3)

    N

    周跨天数

    WEEK_END_DATE

    VARCHAR2(8)

    N

    周结束日期

    TEN_DAY_TIMESPAN

    NUMBER(3)

    N

    旬跨天数

    TEN_DAY_END_DATE

    VARCHAR2(8)

    N

    旬结束日期

    MONTH_TIMESPAN

    NUMBER(3)

    N

    月跨天数

    MONTH_END_DATE

    VARCHAR2(8)

    N

    月结束日期

    QUARTER_TIMESPAN

    NUMBER(3)

    N

    季跨天数

    QUARTER_END_DATE

    VARCHAR2(8)

    N

    季结束日期

    HALF_YEAR_TIMESPAN

    NUMBER(3)

    N

    半年跨天数

    HALF_YEAR_END_DATE

    VARCHAR2(8)

    N

    半年结束日期

    YEAR_TIMESPAN

    NUMBER(3)

    N

    年跨天数

    YEAR_END_DATE

    VARCHAR2(8)

    N

    年结束日期

    BDISABLED

    CHAR(1)

    N

     



    构建时间维度的存储过程包体如下所示
    代码

    create or replace package body PKG_LOAD_DIM_TIME
    as
      
    /************************************
      ** 是否合理自然日
      ** 如果是合理自然日则返回1,否则返回0
      ***********************************
    */
      
    function F_Is_Day_ID
      (
        p_TIME_ID DIW.DW_DIM_TIME.DAY_CODE
    %type
      ) 
    return number
      
    is
        v_Date date;
      
    begin
        v_Date :
    = to_date(p_TIME_ID, 'YYYYMMDD');
        
    return 1;
      exception
        
    when others then
          
    return 0;
      
    end F_Is_Day_ID;

      
    /************************************
      ** 加载时间维度数据
      ***********************************
    */
      
    procedure P_BUILD_DIM_TIME
      (
        p_START_DATE DIW.DW_DIM_TIME.DAY_CODE
    %type,  --开始日期
        p_END_DATE DIW.DW_DIM_TIME.DAY_CODE%type     --结束日期
      )
      
    is
        v_START_DATE date;  
    --开始日期
        v_END_DATE date;    --结束日期
        v_DATE date;

        v_YEAR 
    varchar2(4);
        v_QUARTER 
    varchar2(1);
        v_MONTH 
    varchar2(2);
        v_TEN_DAY 
    varchar2(1);
        v_WEEK 
    varchar2(2);
        v_WEEK_YEAR 
    varchar2(4);
        v_DAY 
    varchar2(2);

      
    begin
        
    --BICODE.PKG_ETL_CONTROLLER.P_ETL_WRITE_LOG('一般','BICODE.PKG_LOAD_DIM_TIME.P_BUILD_DIM_TIME执行开始...');
        execute immediate 'TRUNCATE TABLE DIW.ODS_DIM_TIME';

        
    if F_Is_Day_ID(p_START_DATE)=1 and F_Is_Day_ID(p_END_DATE)=1 then

            v_START_DATE :
    = TO_DATE(p_START_DATE,'YYYYMMDD');
            v_END_DATE :
    = TO_DATE(p_END_DATE,'YYYYMMDD');

            
    if v_END_DATE - v_START_DATE >= 0 then
              
    --开始生成
              for i in 0..v_END_DATE - v_START_DATE loop

                v_DATE :
    = v_START_DATE+i;
                v_YEAR :
    = TO_CHAR(v_DATE,'YYYY');
                v_QUARTER :
    = TO_CHAR(v_DATE,'Q');
                v_MONTH :
    = TO_CHAR(v_DATE,'MM');
                v_TEN_DAY :
    = case
                               
    when TO_CHAR(v_DATE,'DD')<'11' then '1'
                               
    when TO_CHAR(v_DATE,'DD')<'21' then '2'
                               
    when TO_CHAR(v_DATE,'DD')<'32' then '3'
                             
    end;
                
    --周方案一:星期被年分开,实际是7天分段不是自然周
                --v_WEEK := TO_CHAR(v_DATE,'WW');
                --v_WEEK_YEAR := v_YEAR;

                
    --周方案二:本星期星期四所在年
                --v_WEEK := TO_CHAR(v_DATE,'IW');
                --select TO_CHAR(NEXT_DAY(v_DATE-7,2)+3,'YYYY') into v_WEEK_YEAR from dual;
                ----v_WEEK_YEAR := TO_CHAR(NEXT_DAY(v_DATE-7,2)+3,'YYYY');--奇怪的错误??

                
    --周方案三:自然周,周被年分,没找到函数支持。
                select
                  LPAD(TO_CHAR(TRUNC((v_DATE
                  
    -to_date(v_YEAR||'0101','yyyymmdd')
                  
    +DECODE(TO_NUMBER(to_CHAR(to_date(v_YEAR||'0101','yyyymmdd'),'D')),1,7,
                  TO_NUMBER(to_CHAR(to_date(v_YEAR
    ||'0101','yyyymmdd'),'D'))-1)-1)/7+1)),2,'0')
                  
    INTO v_WEEK
                
    from dual;
                v_WEEK_YEAR :
    = v_YEAR;

                v_DAY :
    = TO_CHAR(v_DATE,'DD');

                
    insert into DIW.DW_DIM_TIME
                (
                  DAY_CODE,
                  DAY_LONG_DESC,
                  DAY_MEDIUM_DESC,
                  DAY_SHORT_DESC,
                  WEEK_CODE,
                  WEEK_LONG_DESC,
                  WEEK_MEDIUM_DESC,
                  WEEK_SHORT_DESC,
                  TEN_DAY_CODE,
                  TEN_DAY_LONG_DESC,
                  TEN_DAY_MEDIUM_DESC,
                  TEN_DAY_SHORT_DESC,
                  MONTH_CODE,
                  MONTH_LONG_DESC,
                  MONTH_MEDIUM_DESC,
                  MONTH_SHORT_DESC,
                  QUARTER_CODE,
                  QUARTER_LONG_DESC,
                  QUARTER_MEDIUM_DESC,
                  QUARTER_SHORT_DESC,
                  HALF_YEAR_CODE,
                  HALF_LONG_DESC,
                  HALF_MEDIUM_DESC,
                  HALF_SHORT_DESC,
                  YEAR_CODE,
                  YEAR_LONG_DESC,
                  YEAR_MEDIUM_DESC,
                  YEAR_SHORT_DESC,
                  ALL_TIME_CODE,
                  ALL_TIME_DESC,
                  DAY_TIMESPAN,
                  DAY_END_DATE,
                  WEEK_TIMESPAN,
                  WEEK_END_DATE,
                  TEN_DAY_TIMESPAN,
                  TEN_DAY_END_DATE,
                  MONTH_TIMESPAN,
                  MONTH_END_DATE,
                  QUARTER_TIMESPAN,
                  QUARTER_END_DATE,
                  HALF_YEAR_TIMESPAN,
                  HALF_YEAR_END_DATE,
                  YEAR_TIMESPAN,
                  YEAR_END_DATE
                )
                
    values
                (
                  v_YEAR
    ||v_MONTH||v_DAY,
                  v_YEAR
    ||''||v_MONTH||''||v_DAY||'',
                  
    /*v_MONTH||'月'||*/v_DAY||'',
                  v_YEAR
    ||'-'||v_MONTH||'-'||v_DAY,
                  v_WEEK_YEAR
    ||'W'||v_WEEK,
                  v_WEEK_YEAR
    ||'年第'||v_WEEK||'',
                  
    ''||v_WEEK||'',
                  v_WEEK_YEAR
    ||'-W'||v_WEEK,
                  v_YEAR
    ||v_MONTH||'X'||v_TEN_DAY,
                  v_YEAR
    ||''||v_MONTH||''||decode(v_TEN_DAY,'1','','2','','')||'',
                  decode(v_TEN_DAY,
    '1','','2','','')||'',
                  v_YEAR
    ||'-'||v_MONTH||'-X'||v_TEN_DAY,
                  v_YEAR
    ||v_MONTH,
                  v_YEAR
    ||''||v_MONTH||'',
                  v_MONTH
    ||'',
                  v_YEAR
    ||'-'||v_MONTH,
                  v_YEAR
    ||'Q'||v_QUARTER,
                  v_YEAR
    ||'年第'||v_QUARTER||'季度',
                  
    ''||v_QUARTER||'季度',
                  v_YEAR
    ||'-'||'Q'||v_QUARTER,
                  v_YEAR
    ||'H'||decode(v_QUARTER,'1','1','2','1','2'),
                  v_YEAR
    ||''||decode(v_QUARTER,'1','','2','','')||'半年',
                  decode(v_QUARTER,
    '1','','2','','')||'半年',
                  v_YEAR
    ||'-'||'H'||decode(v_QUARTER,'1','1','2','1','2'),
                  v_YEAR,
                  v_YEAR
    ||'',
                  v_YEAR
    ||'',
                  v_YEAR,
                  
    'ALL',
                  
    'ALL_TIME',
                  
    1,
                  v_YEAR
    ||v_MONTH||v_DAY,
                  
    case
                    
    when
                      TO_CHAR(NEXT_DAY(v_DATE
    -7,2),'YYYY')<v_WEEK_YEAR
                    
    then
                      NEXT_DAY(v_DATE,
    2)-TO_DATE(v_WEEK_YEAR||'0101','YYYYMMDD')
                    
    when
                      TO_CHAR(NEXT_DAY(v_DATE,
    2),'YYYY')>v_WEEK_YEAR
                    
    then
                      TO_DATE(v_WEEK_YEAR
    ||'1231','YYYYMMDD')-NEXT_DAY(v_DATE-7,2)+1
                    
    else 7
                  
    end,
                  
    case
                    
    when
                      TO_CHAR(NEXT_DAY(v_DATE,
    2),'YYYY')>v_WEEK_YEAR
                    
    then v_WEEK_YEAR||'1231'
                    
    else TO_CHAR(NEXT_DAY(v_DATE,2)-1,'YYYYMMDD')
                  
    end,
                  decode(v_TEN_DAY,
    '3',LAST_DAY(v_DATE)-TO_DATE(v_YEAR||v_MONTH||'21','YYYYMMDD')+1,10),
                  decode(v_TEN_DAY,
    '3',TO_CHAR(LAST_DAY(v_DATE),'YYYYMMDD'),'2',v_YEAR||v_MONTH||'20',v_YEAR||v_MONTH||'10'),
                  TO_NUMBER(TO_CHAR(LAST_DAY(v_DATE),
    'DD')),
                  TO_CHAR(LAST_DAY(v_DATE),
    'YYYYMMDD'),
                  decode(v_QUARTER,
    '1',TO_DATE(v_YEAR||'0331','YYYYMMDD')-TO_DATE(v_YEAR||'0101','YYYYMMDD')+1,'2',91,92),
                  decode(v_QUARTER,
    '1',v_YEAR||'0331','2',v_YEAR||'0630','3',v_YEAR||'0930',v_YEAR||'1231'),
                  decode(v_QUARTER,
    '3',184,'4',184,TO_DATE(v_YEAR||'0630','YYYYMMDD')-TO_DATE(v_YEAR||'0101','YYYYMMDD')+1),
                  decode(v_QUARTER,
    '1',v_YEAR||'0630','2',v_YEAR||'0630',v_YEAR||'1231'),
                  TO_DATE(v_YEAR
    ||'1231','YYYYMMDD')-TO_DATE(v_YEAR||'0101','YYYYMMDD')+1,
                  v_YEAR
    ||'1231'
                )
                ;
              
    end loop;
              
    commit;
            
    end if;
        
    end if;
        
        
    --BICODE.PKG_ETL_CONTROLLER.P_UPDATE_ETL_TIME_INFO('DW','DIM_TIME');
        --BICODE.PKG_ETL_CONTROLLER.P_ETL_WRITE_LOG('一般','BICODE.PKG_LOAD_DIM_TIME.P_BUILD_DIM_TIME执行结束...');

        exception
          
    when others then
            
    rollback;
            
    --BICODE.PKG_ETL_CONTROLLER.P_ETL_WRITE_LOG('异常','BICODE.PKG_LOAD_DIM_TIME.P_BUILD_DIM_TIME执行失败...');    
        
      
    end P_BUILD_DIM_TIME;
    end PKG_LOAD_DIM_TIME;


    有时候需要精确度到月份的时间维度表,由于上面的日期时间维度表相对信息比较丰富,可以建立一个视图来影射一个月度时间维度表,如下图所示:


    具体的视图Sql如下所示:

    代码
    CREATE OR REPLACE VIEW DW_DIM_TIME_MONTH_V AS
    SELECT DISTINCT
      T.MONTH_CODE,
      T.MONTH_LONG_DESC,
      T.MONTH_MEDIUM_DESC,
      T.MONTH_SHORT_DESC,
      T.QUARTER_CODE,
      T.QUARTER_LONG_DESC,
      T.QUARTER_MEDIUM_DESC,
      T.QUARTER_SHORT_DESC,
      T.HALF_YEAR_CODE,
      T.HALF_LONG_DESC,
      T.HALF_MEDIUM_DESC,
      T.HALF_SHORT_DESC,
      T.YEAR_CODE,
      T.YEAR_LONG_DESC,
      T.YEAR_MEDIUM_DESC,
      T.YEAR_SHORT_DESC
    FROM DIW.DW_DIM_TIME T;
    主要研究技术:代码生成工具、会员管理系统、客户关系管理软件、病人资料管理软件、Visio二次开发、酒店管理系统、仓库管理系统等共享软件开发
    专注于Winform开发框架/混合式开发框架Web开发框架Bootstrap开发框架微信门户开发框架的研究及应用
      转载请注明出处:
    撰写人:伍华聪  http://www.iqidi.com 
        
  • 相关阅读:
    LeetCode周赛#209
    CodeBlocks相关配置
    LeetCode双周赛#36
    LCCUP 2020 秋季编程大赛 补题
    while和do while区别
    完全背包--piggy-bank
    数组定义在哪里???重要!!!
    01背包---点菜问题
    java源程序命名规则
    hdu1159-----最长公共子序列LCS
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/1738199.html
Copyright © 2020-2023  润新知