Day20:业务分析_学员考勤主题

知识点01:回顾

  1. 拉链表是什么?如何构建拉链表?

    • 拉链表:通过时间来标记变化数据的不同状态
      • startTime:状态开始时间
      • endTime:状态结束时间,最新状态:9999-12-31
    • 步骤
      • step1:增量采集到更新表:ODS
      • step2:更新表与拉链表合并临时表:TMP
        • 修改原有拉链表中的数据:数据发生更新的,并且之前是拉链表最新的状态的数据,endTime修改为当前最新的startTime-1
      • step3:将最新的拉链数据覆盖到拉链表:DW
  2. 报名业务的需求有哪些维度与指标?

    • 指标:报名人数

    • 维度:时间、线上线下、来源渠道、校区、学科、部门

  3. 报名数仓的设计分为几层,每层的功能是什么?

    • ODS:存储原始事务事实表

      • customer_relationship
    • DIM:维度数据层

      • itcast_clazz:班级信息表
        • 校区、学科
      • employee和scrm_deparment
        • 部门
    • DWD:ETL

      • step1:过滤过期的数据,过滤报名数据
      • step2:维度退化,支付时间退化年、月、天、小时
    • DWM:实现了事务事实表与所有维度表的关联

      • 实现4张表的关联
    • DWS:基于小时维度实现各种组合维度的聚合

    • APP:基于更大时间维度对小时维度的结果直接聚合

Day20:业务分析_学员考勤主题

  1. Hive是否支持索引?如何实现的?有什么问题?

    • 支持索引机制:0.7 ~ 3.0

    • 通过MapReduce将索引数据存储在一张索引表中

      • 列的值与文件、在文件中的偏移量映射关系
    • 问题:Hive中索引不会自动根据原表的数据进行更新,必须强制手动更新

  2. ORC文件索引分为几种,各自的应用和特点是什么?

    • row group index:范围匹配、存储列的最大值和最小值

    • bloom filter index:等值匹配、存储列的值

  3. Hive中小文件如何处理?有哪些特殊的属性优化?

    • 小文件处理
      • 避免小文件产生:将结果进行小文件合并
      • 如果处理小文件:提前对小文件进行聚合再处理
    • 特殊属性优化
      • 矢量化查询
      • 零拷贝
      • 关联优化器

知识点02:目标

  1. 学员考勤管理
    • 业务需求
      • 为什么要做考勤管理的分析?
      • 指标与维度分别是什么?
    • 数据来源
      • 有哪些表,哪些字段?
    • 数据仓库设计
      • 如何对原始的数据进行处理,得到可以使用的的数据
      • 对转换后的数据再进行聚合
    • 数据仓库实现
  2. Hive中的优化器的选择
    • RBO
    • CBO
  3. 练习:有效线索主题
    • 基于不同维度统计有效线索的个数

知识点03:学员考勤业务需求

  • 目标掌握学员考勤业务需求

  • 路径

    • step1:需求
    • step2:指标与维度
    • step3:数据来源
  • 实施

    • 需求
      • 通过学员的考勤数据来实现基于时间或者班级校区等不同维度下的考勤指标统计
      • 发现教学管理中的问题,提升学员学习质量
    • 指标与维度
      • 指标
        • 出勤
          • 出勤人数:上课的人数
          • 出勤率:上课人数 / 总人数
        • 迟到:迟到人数、迟到率
        • 请假:请假人数、请假率
        • 旷课:旷课人数、旷课率
      • 维度
        • 时间、班级、校区、学科
    • 数据来源
      • 学员管理系统
      • 分析需要的数据
        • 打卡数据表:班级id、学员id、打卡时间
          • 正常出勤和迟到出勤
        • 请假数据表:班级id、学员id、请假开始时间、请假结束时间
        • 班级总人数表
        • 判断是否是一个有效的出勤或者请假状态:
          • 今天不上课
          • 打卡时间不是上课时间
          • 请假没有被批准
          • ……
  • 小结

    • 掌握学员考勤业务需求

知识点04:学员考勤管理数据

4.1 学生打卡信息表

  • tbh_student_signin_record:学员打卡信息表
    • class_id:班级id
    • student_id:学员id
    • signin_time:打卡时间
    • signin_date:打卡日期
    • 判断:是否是一个有效打卡,如果是有效的,出勤状态是什么?
      • time_table_id:作息时间的id,关联作息时间表
      • share_state:共屏状态
    • 作用:构建每个学生的出勤状态:正常出勤、迟到出勤
COLUMN_NAME COLUMN_COMMENT
id 主键id
normal_class_flag 是否正课 1 正课 2 自习
time_table_id 作息时间id 关联 tbh_school_time_table 或者 tbh_class_time_table
class_id 班级id
student_id 学员id
signin_time 签到时间
signin_date 签到日期
inner_flag 内外网标志 0 外网 1 内网
signin_type 签到类型 1 心跳打卡 2 老师补卡
share_state 共享屏幕状态 0 否 1是,在上午或下午段有共屏记录,则该段所有记录该字段为1,内网默认为1 外网默认为0
inner_ip 内网ip地址

4.2 班级作息时间表

  • tbh_class_time_table:班级作息时间表
    • 每个班级每天上午、下午、晚上的上课时间和下课时间
    • 作用:判断学员的打卡是否是一个有效的打卡
COLUMN_NAME COLUMN_COMMENT
id 主键id
class_id 班级id
morning_template_id 上午出勤模板id
morning_begin_time 上午开始时间
morning_end_time 上午结束时间
afternoon_template_id 下午出勤模板id
afternoon_begin_time 下午开始时间
afternoon_end_time 下午结束时间
evening_template_id 晚上出勤模板id
evening_begin_time 晚上开始时间
evening_end_time 晚上结束时间
use_begin_date 使用开始日期
use_end_date 使用结束日期
create_time 创建时间
create_person 创建人
remark 备注

4.3 班级课表

  • course_table_upload_detail:班级排课信息表

    • class_id:班级id

    • class_date:班级上课的日期

    • content:班级上课的内容

      • 如果内容为null,或者今天上课的内容是开班典礼
    • 作用:用于判断当前的打卡是否是一个有效的打卡、或者一个请假是否是一个有效的请假

COLUMN_NAME COLUMN_COMMENT
id id
base_id 课程主表id
class_id 班级id
class_date 上课日期
content 课程内容
teacher_id 老师id
teacher_name 老师名字
job_number 工号
classroom_id 教室id
classroom_name 教室名称
is_outline 是否大纲 0 否 1 是
class_mode 上课模式 0 传统全天 1 AB上午 2 AB下午 3 线上直播
is_stage_exam 是否阶段考试(0:否 1:是)
is_pay 代课费(0:无 1:有)
tutor_teacher_id 晚自习辅导老师id
tutor_teacher_name 辅导老师姓名
tutor_job_number 晚自习辅导老师工号
is_subsidy 晚自习补贴(0:无 1:有)
answer_teacher_id 答疑老师id
answer_teacher_name 答疑老师姓名
answer_job_number 答疑老师工号
remark 备注
create_time 创建时间

4.4 在读学员人数信息表

  • class_studying_student_count:班级学员人数表
    • 记录每个班级的总人数
    • class_id:班级id
    • studying_student_count:班级的总人数
COLUMN_NAME COLUMN_COMMENT
id
school_id 校区id
subject_id 学科id
class_id 班级id
studying_student_count 在读班级人数
studying_date 在读日期

4.5 学生请假申请表

  • student_leave_apply:学员请假信息表

    • class_id:班级id

    • student_id:学员id

    • audit_state:是否批准

    • begin_time:请假开始时间

    • end_time:请假结束时间

    • 作用:用于统计每个班级的请假人数

      • 对请假的合法性做判断
COLUMN_NAME COLUMN_COMMENT
id 序列id
class_id 班级id
student_id 学员id
audit_state 审核状态 0 待审核 1 通过 2 不通过
audit_person 审核人
audit_time 审核时间
audit_remark 审核备注
leave_type 请假类型 1 请假 2 销假
leave_reason 请假原因 1 事假 2 病假
begin_time 请假开始时间
begin_time_type 1:上午 2:下午
end_time 请假结束时间
end_time_type 1:上午 2:下午
days 请假/已休天数
cancel_state 撤销状态 0 未撤销 1 已撤销
cancel_time 撤销时间
old_leave_id 原请假id,只有leave_type =2 销假的时候才有
leave_remark 请假/销假说明
valid_state 是否有效(0:无效 1:有效)
create_time 创建时间

Day20:业务分析_学员考勤主题

知识点05:数仓设计:ODS与DIM层

  • 目标:了解考勤管理数仓中ODS与DIM层的设计

  • 实施

    • ODS:事务事实表

      • 学员打卡信息表:记录了所有打卡信息,用于描述出勤事实
        • 正常出勤、迟到出勤
        • 出勤人数:正常出勤 + 迟到出勤
        • 迟到人数
      • 学员请假信息表:记录所有请假信息,用于描述请假事实
        • 请假人数
    • DIM:维度信息表

      • 班级作息时间表:判断打卡或者请假是否合法的

      • 班级排课信息表:判断打卡或者请假是否合法的

      • 班级人数信息表:记录每个班级的总人数

        • 用于计算旷课人数

        • 用于计算出勤状态的比例

  • 小结

    • 了解考勤管理数仓中ODS与DIM层的设计

知识点06:数仓设计:DWD与DWM层

  • 目标:了解考勤管理数仓中DWD与DWM层的设计

  • 实施

    • DWD:明细数据层

      • 无具体ETL需求,不做DWD处理
    • DWM:中间数据层

      • 最终目标
时间	班级	上午出勤 上午出勤率  上午迟到人数 上午迟到率  上午请假人数 上午请假率 上午旷课人数 上午旷课率
5-14  001	98      98%        10        10%        2         2%         0			
时间	班级	上午出勤人数   上午迟到人数   上午请假人数  上午旷课人数 
 5-14  001	  98          10            2          0	
  - 打卡信息表

  - 请假信息表
  
    |
    
  - 班级出勤状态表
  时间	班级	上午出勤人数   上午迟到人数
        5-14  001	  98          10       
  • 班级请假状态表
        时间	班级	   上午请假人数  
        5-14  001          2       
  • 班级旷课状态表

    - 总人数表 - 出勤状态表 - 请假状态表
     
    
     时间	班级	  上午旷课人数 
         5-14  001	       0	
    
    • 目标:构建班级出勤状态表、班级请假状态表、班级旷课状态表

    • 班级出勤状态表

          时间 			班级id	上午出勤	上午迟到  下午出勤 下午迟到  晚上出勤	晚上迟到
      
      • 班级请假状态表
      时间 			班级id	上午请假	下午请假	晚上请假
          ```
      
        - 班级旷课状态表
          
          ```
      时间 			班级id	上午旷课	下午旷课	晚上旷课
          ```
      
      

    • 班级出勤状态表分析

      • 数据:学员打卡信息表

        班级id		学员id	 打卡时间			
        001				1	   2020-01-01 12:30:00	   	   
        001				1      2020-01-01 15:30:00
        001				1      2020-01-01 19:00:00
        
      • 目标:班级出勤状态表

        时间 			班级id	上午出勤	上午迟到  下午出勤 下午迟到  晚上出勤	晚上迟到
        2020-01-01		001		30			10		30		2		30			1
        
      • 步骤

        • step1:先将学员打卡信息转换为学员出勤状态信息

          班级id	学员id	 	date		 上午				 下午			  晚上
          001			1						正常				迟到			未出勤
          001			2						迟到			    正常			正常
          
        select 
            case 打卡时间 when 上课前40分钟到下课之间  then  出勤
          	when 上课后10分钟到下课之间 then  迟到
            	else 其他
          from ods_student_signin
  • 出勤:上课前40分钟到下课之间

    • 迟到:上课后10分钟到下课之间

      • step2:基于学员出勤状态信息统计班级出勤人数表

        时间 			班级id	上午出勤	上午迟到  下午出勤 下午迟到  晚上出勤	晚上迟到
        2020-01-01	  001		30			10		30		2		30			1
        
        select
          count(case when 上午状态 = 正常 or 迟到 then 学员id else null end) as 上午出勤人数
          count(case when 上午状态 = 迟到 then 学员id else null end) as 上午迟到人数
          ……
        from table 
        group by class_id ,date
        
    • 班级请假状态表分析

      • ODS:学员请假信息表

        班级id		学员id			请假开始时间		请假结束时间			是否合法
        001				1				12:00:00		18:00:00			0
        001				2				12:00:00		18:00:00			1
        
      • DWM:班级请假人数报表

        时间			班级id		上午请假人数		下午请假人数		晚上请假人数
        2020-01-01		001				3			2					4
        
      • 实现

      select
         class_id,
         date,
         count(disintct 学员id) as 上午请假人数
      from table
      where 请假时间 < 上午上课时间 and 请假时间 > 上午下课时间
      group by class_id,date;
      join
      select
         class_id,
         date,
         count(disintct 学员id) as 下午请假人数
      from table
      where 请假时间 < 下午上课时间 and 请假时间 > 下午下课时间
      group by class_id,date;
      join
      select
         class_id,
         date,
         count(disintct 学员id) as 晚上请假人数
      from table
      where 请假时间 < 晚上上课时间 and 请假时间 > 晚上下课时间
      group by class_id,date;
      
      on classId and date
      
    • 班级旷课状态表分析

      • DWM

        • 班级出勤状态表

          时间 			班级id	上午出勤	上午迟到  下午出勤 下午迟到  晚上出勤	晚上迟到
          2020-01-01		001		25			5		25		2		25		4
          
        • 班级请假人数表

          时间			  班级id		上午请假人数		下午请假人数		晚上请假人数
          2020-01-01		001				3			2					4
          
        • DIM:班级总人数表

          班级id		总人数
          001				30
          
      • DWM:班级旷课信息表

        时间				班级		上午旷课人数		下午旷课人数		晚上旷课人数
        2020-01-01		001			2				3				1
        

  • 小结

    • 了解考勤管理数仓中DWD与DWM层的设计

知识点07:数仓设计:DWS与APP层

  • 目标:了解考勤管理数仓中DWS与APP层的设计

  • 实施

    • DWM

      • 出勤状态
      时间	班级	出勤人数	迟到人数
      
      • 请假状态
        时间	班级	请假人数
      
      • 旷课装填
        时间	班级	旷课人数
      
    • DWS:汇总数据层

      • 关联

        时间		班级		出勤人数		迟到人数		请假人数		旷课人数
        
      • 按照天维度做基础聚合,得到天维度下的结果

        时间【天】	班级	上午指标……		下午指标……		晚上指标……
        
    • APP:应用数据层

      • 最终得到每个时间维度下对应每个班级的汇总指标

        时间【天、月、年】	班级	上午指标……		下午指标……		晚上指标……
        
  • 小结

    • 了解考勤管理数仓中DWS与APP层的设计

知识点08:Hive分析优化器与CBO引擎

  • 目标:掌握Hive分析优化器与CBO引擎的使用

  • 路径

    • step1:优化器
    • step2:CBO
    • step3:分析优化器Analyze
  • 实施

    • 优化器

      • 问题:关于底层优化器的选择的问题

        • RBO:基于规则的优化引擎,几乎所有数据库工具默认的优化引擎

          • 按照规定的规则,源码中定义所有的规则,只要符合条件,就按照固定的规则来处理
        • CBO:基于代价的优化引擎

          • 按照代价的判断的性能来具体选择一种代价最小的方式来处理数据
        • 举个栗子

          select * from table where age = 20
          
          • 条件:age这一列有索引,整张表有100条数据,age=20的数据有90条
          • 结果:返回这90条数据内容
          • RBO:按照固定的规则,来实现处理,走了索引,通过索引查询到这90条数据对应的位置,再去读这90条数据
          • CBO:根据代价实现判断,发现全表扫描比走索引更快,所以CBO引擎会选择走全表扫描来得到这90条数据
    • CBO

      • 功能:基于各种方式所要付出的代价来衡量,使用代价相对较小的方式来实现底层的计算

      • 要求:要想用CBO,必须提前准备这些数据的一些元数据信息,列的元数据信息【哪些列,每种列的值有多少个】

      • 属性

        set hive.cbo.enable=true;
        set hive.compute.query.using.stats=true;
        set hive.stats.fetch.column.stats=true;
        set hive.stats.fetch.partition.stats=true;
        
    • 分析优化器Analyze

      • 功能:通过底层执行一个MapReduce,提前构建这张表中的列、分区等数据的元数据,搭配CBO引擎来使用

      • 使用

        ANALYZE TABLE tablename
        [PARTITION(partcol1[=val1], partcol2[=val2], ...)]
        COMPUTE STATISTICS [noscan];
        
        ANALYZE TABLE tablename
        [PARTITION(partcol1[=val1], partcol2[=val2], ...)]
        COMPUTE STATISTICS FOR COLUMNS ( columns name1, columns name2...) [noscan];
        
        • noscan:不读取文件,如果不读取文件,只能获取到一些基本的信息
  • 小结

    • 什么是CBO?如何使用CBO?
      • CBO:基于代价的优化器引擎,根据所有方案需要付出的代价选择最小的代价的方案来实现执行
      • 使用
        • step1:先通过分析优化器anlayze构建元数据
        • step2:开启属性

知识点09:数仓实现:ODS层与DIM层

  • 目标实现ODS层与DIM层的构建

  • 实施

    • ODS

      • 分析

        • 学员打卡信息表:出勤和迟到事实
        • 学员请假信息表:请假事实
      • 实现

        • 学生打卡记录表

          drop table itcast_ods.student_signin_ods;
          CREATE TABLE IF NOT EXISTS itcast_ods.student_signin_ods (
              id                int,
              normal_class_flag int           comment '是否正课 1 正课 2 自习 3 休息',
              time_table_id     int           comment '作息时间id normal_class_flag=2 关联tbh_school_time_table 或者 normal_class_flag=1 关联 tbh_class_time_table',
              class_id          int           comment '班级id',
              student_id        int           comment '学员id',
              signin_time       String       comment '签到时间',
              signin_date       String          comment '签到日期',
              inner_flag        int           comment '内外网标志  0 外网 1 内网',
              signin_type       int           comment '签到类型 1 心跳打卡 2 老师补卡 3 直播打卡',
              share_state       int            comment '共享屏幕状态 0 否 1是  在上午或下午段有共屏记录,则该段所有记录该字段为1,内网默认为1 外网默认为0   (暂不用)',
              inner_ip          String          comment '内网ip地址',
              create_time       String       comment '创建时间')
          comment '学生打卡记录表'
          PARTITIONED BY (dt STRING)
          ROW FORMAT DELIMITED 
          FIELDS TERMINATED BY '\t'
          stored as orc
          location '/user/hive/warehouse/itcast_ods.db/student_signin_ods'
          TBLPROPERTIES ('orc.compress'='SNAPPY','orc.bloom.filter.columns'='time_table_id,class_id,signin_date,share_state');
          
          sqoop import \
          --connect jdbc:mysql://node3:3306/teach \
          --username root \
          --password 123456 \
          --driver com.mysql.jdbc.Driver \
          --query 'select *, FROM_UNIXTIME(unix_timestamp(),"%Y-%m-%d") as dt from tbh_student_signin_record where $CONDITIONS' \
          --hcatalog-database itcast_ods \
          --hcatalog-table student_signin_ods \
          --hcatalog-storage-stanza 'stored as orc tblproperties ("orc.compress"="SNAPPY")' \
          -m 1
          
        • 学生请假记录表

          drop table itcast_ods.student_leave_apply_ods;
          CREATE TABLE IF NOT EXISTS itcast_ods.student_leave_apply_ods (
              id              int,
              class_id        int           comment '班级id',
              student_id      int           comment '学员id',
              audit_state     int        comment '审核状态 0 待审核 1 通过 2 不通过',
              audit_person    int           comment '审核人',
              audit_time      String      comment '审核时间',
              audit_remark    String     comment '审核备注',
              leave_type      int           comment '请假类型  1 请假 2 销假 (查询是否请假不用过滤此类型,通过有效状态来判断)',
              leave_reason    int           comment '请假原因  1 事假 2 病假',
              begin_time      String      comment '请假开始时间',
              begin_time_type int           comment '1:上午 2:下午 3:晚自习',
              end_time        String      comment '请假结束时间',
              end_time_type   int           comment '1:上午 2:下午 3:晚自习',
              days            float         comment '请假/已休天数',
              cancel_state    int         comment '撤销状态  0 未撤销 1 已撤销',
              cancel_time     String      comment '撤销时间',
              old_leave_id    int           comment '原请假id,只有leave_type =2 销假的时候才有',
              leave_remark    String     comment '请假/销假说明',
              valid_state     int        comment '是否有效(0:无效 1:有效)',
              create_time     String      comment '创建时间')
          comment '学生请假申请表'
          PARTITIONED BY (dt STRING)
          ROW FORMAT DELIMITED 
          FIELDS TERMINATED BY '\t'
          stored as orc
          location '/user/hive/warehouse/itcast_ods.db/student_leave_apply_ods'
          TBLPROPERTIES ('orc.compress'='SNAPPY','orc.bloom.filter.columns'='class_id,audit_state,cancel_state,valid_state');
          
          sqoop import \
          --connect jdbc:mysql://node3:3306/teach \
          --username root \
          --password 123456 \
          --driver com.mysql.jdbc.Driver \
          --query 'select *, FROM_UNIXTIME(unix_timestamp(),"%Y-%m-%d") as dt from student_leave_apply where $CONDITIONS' \
          --hcatalog-database itcast_ods \
          --hcatalog-table student_leave_apply_ods \
          --hcatalog-storage-stanza 'stored as orc tblproperties ("orc.compress"="SNAPPY")' \
          -m 1
          
    • DIM

      • 分析

        • 班级作息时间表
      • 班级排课信息表

    • 班级总人数表

      • 实现

        • 在读学员人数表

          set hive.exec.orc.compression.strategy=COMPRESSION;
          drop table itcast_dimen.class_studying_student_count_dimen;
          CREATE TABLE IF NOT EXISTS itcast_dimen.class_studying_student_count_dimen (
              id                     int,
              school_id              int  comment '校区id',
              subject_id             int  comment '学科id',
              class_id               int  comment '班级id',
              studying_student_count int  comment '在读班级人数',
              studying_date          STRING comment '在读日期')
          comment '在读班级的每天在读学员人数'
          PARTITIONED BY (dt STRING)
          ROW FORMAT DELIMITED 
          FIELDS TERMINATED BY '\t'
          

        stored as orc
        location ‘/user/hive/warehouse/itcast_dimen.db/class_studying_student_count_dimen’
        TBLPROPERTIES (‘orc.compress’=‘SNAPPY’,‘orc.bloom.filter.columns’=‘studying_student_count,studying_date’);

        
        ```shell
        sqoop import \
        --connect jdbc:mysql://node3:3306/teach \
        --username root \
        --password 123456 \
        --driver com.mysql.jdbc.Driver \
        --query 'select id, school_id, subject_id, class_id, ifnull(studying_student_count,0) studying_student_count, studying_date, FROM_UNIXTIME(unix_timestamp(),"%Y-%m-%d") as dt from class_studying_student_count where $CONDITIONS' \
        --hcatalog-database itcast_dimen \
        --hcatalog-table class_studying_student_count_dimen \
        --hcatalog-storage-stanza 'stored as orc tblproperties ("orc.compress"="SNAPPY")' \
        -m 1
        
        • 班级排课表

          drop table itcast_dimen.course_table_upload_detail_dimen;
          CREATE TABLE IF NOT EXISTS itcast_dimen.course_table_upload_detail_dimen
          (
              id                  int       comment 'id',
              base_id             int         comment '课程主表id',
              class_id            int         comment '班级id',
              class_date          STRING      comment '上课日期',
              content             STRING     comment '课程内容',
              teacher_id          int         comment '老师id',
              teacher_name        STRING     comment '老师名字',
              job_number          STRING     comment '工号',
              classroom_id        int         comment '教室id',
              classroom_name      STRING     comment '教室名称',
              is_outline          int         comment '是否大纲 0 否 1 是',
              class_mode          int         comment '上课模式 0 传统全天 1 AB上午 2 AB下午 3 线上直播',
              is_stage_exam       int         comment '是否阶段考试(0:否 1:是)',
              is_pay              int         comment '代课费(0:无 1:有)',
              tutor_teacher_id    int         comment '晚自习辅导老师id',
              tutor_teacher_name  STRING     comment '辅导老师姓名',
              tutor_job_number    STRING     comment '晚自习辅导老师工号',
              is_subsidy          int         comment '晚自习补贴(0:无 1:有)',
              answer_teacher_id   int         comment '答疑老师id',
              answer_teacher_name STRING     comment '答疑老师姓名',
              answer_job_number   STRING     comment '答疑老师工号',
              remark              STRING        comment '备注',
              create_time         STRING      comment '创建时间')
          comment '班级课表明细表'
          PARTITIONED BY (dt STRING)
          ROW FORMAT DELIMITED 
          FIELDS TERMINATED BY '\t'
          

        stored as orc
        location ‘/user/hive/warehouse/itcast_dimen.db/course_table_upload_detail_dimen’
        TBLPROPERTIES (‘orc.compress’=‘SNAPPY’,‘orc.bloom.filter.columns’=‘class_id,class_date’);

        
        ```shell
        sqoop import \
        --connect jdbc:mysql://node3:3306/teach \
        --username root \
        --password 123456 \
        --driver com.mysql.jdbc.Driver \
        --query 'select id,
            base_id,
            class_id,
            class_date,
            content,
            teacher_id,
            teacher_name,
            job_number,
            classroom_id,
            classroom_name,
            is_outline,
            class_mode,
            is_stage_exam,
            is_pay,
            tutor_teacher_id,
            tutor_teacher_name,
            tutor_job_number,
            is_subsidy,
            answer_teacher_id,
            answer_teacher_name,
            answer_job_number,
            remark,
            create_time,
            FROM_UNIXTIME(unix_timestamp(),"%Y-%m-%d") as dt from course_table_upload_detail where $CONDITIONS' \
        --hcatalog-database itcast_dimen \
        --hcatalog-table course_table_upload_detail_dimen \
        --hcatalog-storage-stanza 'stored as orc tblproperties ("orc.compress"="SNAPPY")' \
        -m 1
        
        • 班级作息时间表
        drop table itcast_dimen.class_time_dimen;
        CREATE TABLE IF NOT EXISTS itcast_dimen.class_time_dimen (
            id                     int,
            class_id              int              comment '班级id',
            morning_template_id   int              comment '上午出勤模板id',
            morning_begin_time    STRING         comment '上午开始时间',
            morning_end_time      STRING         comment '上午结束时间',
            afternoon_template_id int              comment '下午出勤模板id',
            afternoon_begin_time  STRING         comment '下午开始时间',
            afternoon_end_time    STRING         comment '下午结束时间',
            evening_template_id   int              comment '晚上出勤模板id',
            evening_begin_time    STRING         comment '晚上开始时间',
            evening_end_time      STRING         comment '晚上结束时间',
            use_begin_date        STRING         comment '使用开始日期',
            use_end_date          STRING         comment '使用结束日期',
            create_time           STRING       comment '创建时间',
            create_person         int              comment '创建人',
            remark                STRING      comment '备注')
        comment '班级作息时间表'
        PARTITIONED BY (dt STRING)
        ROW FORMAT DELIMITED 
        FIELDS TERMINATED BY '\t'
       stored as orc
        location '/user/hive/warehouse/itcast_dimen.db/class_time_dimen'
        TBLPROPERTIES ('orc.compress'='SNAPPY','orc.bloom.filter.columns'='id,class_id');
        sqoop import \
        --connect jdbc:mysql://node3:3306/teach \
        --username root \
        --password 123456 \
        --driver com.mysql.jdbc.Driver \
        --query 'select *, FROM_UNIXTIME(unix_timestamp(),"%Y-%m-%d") as dt from tbh_class_time_table where $CONDITIONS' \
        --hcatalog-database itcast_dimen \
      --hcatalog-table class_time_dimen \
        --hcatalog-storage-stanza 'stored as orc tblproperties ("orc.compress"="SNAPPY")' \
        -m 1
  • 小结

    • 实现ODS层与DIM层的构建

知识点10:数仓实现:DWM层出勤

  • 目标实现DWM层出勤状态表的构建

  • 实施

    • 分析

      • ODS:学员打卡信息表

        班级id		学员id			打卡时间					打卡日期
        001				1			2020-01-01 12:30:00			2020-01-01
        
      • DWM

        • step1:先将学员打卡信息转换为学员出勤状态信息

          班级id	学员id	 			 上午				 下午			  晚上
          001			1					正常				迟到			 未出勤
          001			2					迟到			    正常			正常
          
        • step2:基于学员出勤状态信息统计班级出勤人数表

          时间 			班级id	上午出勤	上午迟到  下午出勤 下午迟到  晚上出勤	晚上迟到
          2020-01-01	  001		30			10		30		2		30			1
          
      • SQL实现:判断:0.正常出勤、1.迟到、2.其他

        • 判断打卡时间是否在上课时间范围内
          • 出勤时间范围:上课前40分钟 ~ 下课时间
            • 迟到时间范围:上课十分钟后 ~ 下课时间
            • 关联班级作息时间表
        • 判断打卡是否是一个合法的打卡
          • 今天是否是正课
          • 关联班级排课表
    • 实现学员出勤状态表

      • 建表:学员出勤状态表

        drop table itcast_dwm.student_attendance_dwm;
        CREATE TABLE IF NOT EXISTS itcast_dwm.student_attendance_dwm (
            dateinfo        String        comment '日期',
            class_id          int           comment '班级id',
            student_id        int           comment '学员id',
            morning_att       String       comment '上午出勤情况:0.正常出勤、1.迟到、2.其他(请假+旷课)',
            afternoon_att    String        comment '下午出勤情况:0.正常出勤、1.迟到、2.其他(请假+旷课)',
            evening_att       String        comment '晚自习出勤情况:0.正常出勤、1.迟到、2.其他(请假+旷课)')
        comment '学生出勤(正常出勤和迟到)数据'
        PARTITIONED BY (yearinfo STRING, monthinfo STRING, dayinfo STRING)
        ROW FORMAT DELIMITED 
        FIELDS TERMINATED BY '\t'
        stored as orc
        location '/user/hive/warehouse/itcast_dwm.db/student_attendance_dwm';
        
        --内存不足,执行以下语句
        drop table itcast_dwm.student_attendance_dwm;
        CREATE TABLE IF NOT EXISTS itcast_dwm.student_attendance_dwm (
            dateinfo        String        comment '日期',
          class_id          int           comment '班级id',
            student_id        int           comment '学员id',
            morning_att       String       comment '上午出勤情况:0.正常出勤、1.迟到、2.其他(请假+旷课)',
            afternoon_att    String        comment '下午出勤情况:0.正常出勤、1.迟到、2.其他(请假+旷课)',
            evening_att       String        comment '晚自习出勤情况:0.正常出勤、1.迟到、2.其他(请假+旷课)')
        comment '学生出勤(正常出勤和迟到)数据'
        PARTITIONED BY (yearinfo STRING, monthinfo STRING, dayinfo STRING)
        ROW FORMAT DELIMITED 
        FIELDS TERMINATED BY '\t'
        location '/user/hive/warehouse/itcast_dwm.db/student_attendance_dwm';
        
      • 开启属性

        --分区
        SET hive.exec.dynamic.partition=true;
        SET hive.exec.dynamic.partition.mode=nonstrict;
        set hive.exec.max.dynamic.partitions.pernode=10000;
        set hive.exec.max.dynamic.partitions=100000;
        set hive.exec.max.created.files=150000;
        --hive压缩
        set hive.exec.compress.intermediate=true;
        set hive.exec.compress.output=true;
        --写入时压缩生效
        set hive.exec.orc.compression.strategy=COMPRESSION;
        --分桶
        set hive.enforce.bucketing=true;
        set hive.enforce.sorting=true;
        set hive.optimize.bucketmapjoin = true;
        set hive.auto.convert.sortmerge.join=true;
        set hive.auto.convert.sortmerge.join.noconditionaltask=true;
        --并行执行
        set hive.exec.parallel=true;
        set hive.exec.parallel.thread.number=8;
        --矢量化查询
        set hive.vectorized.execution.enabled=true;
        --关联优化器
        set hive.optimize.correlation=true;
        --读取零拷贝
        set hive.exec.orc.zerocopy=true;
        --join数据倾斜
        set hive.optimize.skewjoin=true;
        set hive.optimize.skewjoin.compiletime=true;
        -- group倾斜
        set hive.groupby.skewindata=true;
        
      • 实现学员出勤状态表

        • 分析的SQL

           -- 在上课前40分钟~上课时间点10分钟之内,为正常打卡0;在上课后10分钟~放学时间之内,为迟到1;否则为2.
              --上午的状态
              if(
          		--第一个参数是判断条件,判断是否出勤了
                  sum(
                      if(
                          (
                              cast(
          					--上午上课时间
                                  (unix_timestamp(concat_ws(' ', so.signin_date, ti.morning_begin_time), 'yyyy-MM-dd HH:mm:ss')
                                  -
          						--签到时间
                                  unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS'))
                                  / 60
                                  as INT
                              ) <= 40
                          )
                          and 
                          (
          					--签到时间
                              unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS') 
                              < 
          					--上午结束时间
                              unix_timestamp(concat_ws(' ', so.signin_date, ti.morning_end_time), 'yyyy-MM-dd HH:mm:ss')
                          ),
          			--如果满足这个条件就返回1,不满足返回0
                      1, 0)
          			--返回1结果大于0,条件成立,执行true的结果
          			--返回0结果,条件不成立,执行false的结果,返回2
                  ) > 0,
          		--if层的第二个参数,true的结果,又是一个if判断,用于判断是正常还是迟到,正常:0,迟到:1
                  if(
                      sum(
                          if(
                              (
                                  cast(
                                      (
          								--上午上课时间
                                          unix_timestamp(concat_ws(' ', so.signin_date, ti.morning_begin_time), 'yyyy-MM-dd HH:mm:ss')
                                          -
          								--签到时间
                                          unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS')
                                      )
                                      / 60
                                      as INT
                                  ) <= 40
                              )
                              and 
                              (
          			
                                   cast(
                                      (
          								--签到时间
                                          unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS')
                                          -
          								--上午上课时间
                                          unix_timestamp(concat_ws(' ', so.signin_date, ti.morning_begin_time), 'yyyy-MM-dd HH:mm:ss')
                                      )
                                      / 60
                                      as INT
          							--小于10分钟
                                  ) <= 10
                              ),
          				--如果满足以上条件,返回1,
          				--如果不满足返回0
                          1, 0)
          			--如果上一个条件满足,大于0,返回0,正常出勤
          			--如果不满足上一条条件,返回1,迟到出勤
                      ) > 0,
                      0, 1
                  ),
          		--第三个参数,false的结果,非法打卡
                  2
              ) as morning_att, 
          
        • 实现的SQL

        INSERT overwrite table  itcast_dwm.student_attendance_dwm PARTITION(yearinfo, monthinfo, dayinfo)
        SELECT 
            course.class_date,--上课日期
            course.class_id,--班级id
            so.student_id,--学生id
            -- 在上课前40分钟~上课时间点10分钟之内,为正常打卡0;在上课后10分钟~放学时间之内,为迟到1;否则为2.
            --上午的状态
            if(
                sum(
                    if(
                        (
                            cast(
                                (unix_timestamp(concat_ws(' ', so.signin_date, ti.morning_begin_time), 'yyyy-MM-dd HH:mm:ss')
                                -
                                unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS'))
                                / 60
                                as INT
                            ) <= 40
                        )
                        and 
                        (
                            unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS') 
                            < 
                            unix_timestamp(concat_ws(' ', so.signin_date, ti.morning_end_time), 'yyyy-MM-dd HH:mm:ss')
                        ),
                    1, 0)
                ) > 0,
                if(
                    sum(
                        if(
                            (
                                cast(
                                    (
                                        unix_timestamp(concat_ws(' ', so.signin_date, ti.morning_begin_time), 'yyyy-MM-dd HH:mm:ss')
                                        -
                                        unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS')
                                    )
                                    / 60
                                    as INT
                                ) <= 40
                            )
                            and 
                            (
                                 cast(
                                    (
                                        unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS')
                                        -
                                        unix_timestamp(concat_ws(' ', so.signin_date, ti.morning_begin_time), 'yyyy-MM-dd HH:mm:ss')
                                    )
                                    / 60
                                    as INT
                                ) <= 10
                            ),
                        1, 0)
                    ) > 0,
                    0, 1
                ),
                2
            ) as morning_att, 
            -- 在上课前40分钟~上课时间点10分钟之内,为正常打卡0;在上课后10分钟~放学时间之内,为迟到1;否则为2.
            --下午的转态
            if(
                --判断是否正常出勤(包含迟到的)
                sum(
                    if(
                        (
                            cast(
                                (unix_timestamp(concat_ws(' ', so.signin_date, ti.afternoon_begin_time), 'yyyy-MM-dd HH:mm:ss')
                                -
                                unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS'))
                                / 60
                                as INT
                            ) <= 40
                        )
                        and 
                        (
                            unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS') 
                            < 
                            unix_timestamp(concat_ws(' ', so.signin_date, ti.afternoon_end_time), 'yyyy-MM-dd HH:mm:ss')
                        ),
                    1, 0)
                ) > 0,
                
                --正常出勤,但迟到了,判断并标记
                if(
                    sum(
                        if(
                            (
                                cast(
                                    (
                                        unix_timestamp(concat_ws(' ', so.signin_date, ti.afternoon_begin_time), 'yyyy-MM-dd HH:mm:ss')
                                        -
                                        unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS')
                                    )
                                    / 60
                                    as INT
                                ) <= 40
                            )
                            and 
                            (
                                 cast(
                                    (
                                        unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS')
                                        -
                                        unix_timestamp(concat_ws(' ', so.signin_date, ti.afternoon_begin_time), 'yyyy-MM-dd HH:mm:ss')
                                    )
                                    / 60
                                    as INT
                                ) <= 10
                            ),
                        1, 0)
                    ) > 0,
                    0, 1
                ),
                2
            ) as  afternoon_att, 
            -- 在上课前40分钟~上课时间点10分钟之内,为正常打卡0;在上课后10分钟~放学时间之内,为迟到1;否则为2.
            --晚上的状态
            if(
                --判断是否正常出勤(包含迟到的)
                sum(
                    if(
                        (
                            cast(
                                (unix_timestamp(concat_ws(' ', so.signin_date, ti.evening_begin_time), 'yyyy-MM-dd HH:mm:ss')
                                -
                                unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS'))
                                / 60
                                as INT
                            ) <= 40
                        )
                        and 
                        (
                            unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS') 
                            < 
                            unix_timestamp(concat_ws(' ', so.signin_date, ti.evening_end_time), 'yyyy-MM-dd HH:mm:ss')
                        ),
                    1, 0)
                ) > 0,
                
                --正常出勤,但迟到了,判断并标记
                if(
                    sum(
                        if(
                            (
                                cast(
                                    (
                                        unix_timestamp(concat_ws(' ', so.signin_date, ti.evening_begin_time), 'yyyy-MM-dd HH:mm:ss')
                                        -
                                        unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS')
                                    )
                                    / 60
                                    as INT
                                ) <= 40
                            )
                            and 
                            (
                                 cast(
                                    (
                                        unix_timestamp(so.signin_time, 'yyyy-MM-dd HH:mm:ss.SSS')
                                        -
                                        unix_timestamp(concat_ws(' ', so.signin_date, ti.evening_begin_time), 'yyyy-MM-dd HH:mm:ss')
                                    )
                                    / 60
                                    as INT
                                ) <= 10
                            ),
                        1, 0)
                    ) > 0,
                    0, 1
                ),
                2
            ) as  evening_att,
            substr(course.class_date, 1, 4) as yearinfo, 
            substr(course.class_date, 6, 2) monthinfo, 
            substr(course.class_date, 9, 2) dayinfo
        from itcast_ods.student_signin_ods so
            --班级课表关联学生签到表
            --通过班级id和对应日期进行关联,并且学生正常开启共屏
            LEFT JOIN itcast_dimen.course_table_upload_detail_dimen course  on course.class_id = so.class_id and so.signin_date=course.class_date AND so.share_state=1
            --再关联班级上课时间表
            LEFT JOIN itcast_dimen.class_time_dimen ti on so.time_table_id=ti.id
            --课表中课程内容不为 空并且不是开班典礼
        WHERE course.content IS NOT NULL AND course.content != '开班典礼'
            --按照班级和日期以及学生进行分组
        GROUP BY course.class_date, course.class_id, so.student_id;
        
    • 实现班级出勤状态表

  count(case morning_att when 0 or 1 then student_id else null end) as 上午出勤人数
  count(case morning_att when  1 then student_id else null end) as 上午迟到人数
  • 建表
   drop table itcast_dwm.class_attendance_dwm;
   CREATE TABLE IF NOT EXISTS itcast_dwm.class_attendance_dwm (
       dateinfo        String        comment '日期',
       class_id          int           comment '班级id',
       morning_att_count       String         comment '上午出勤人数',
       afternoon_att_count      String        comment '下午出勤人数',
       evening_att_count       String        comment '晚自习出勤人数',
       morning_late_count       String         comment '上午迟到人数',
       afternoon_late_count      String        comment '下午迟到人数',
       evening_late_count       String        comment '晚自习迟到人数')
   comment '学生出勤(正常出勤和迟到)数据'
   PARTITIONED BY (yearinfo STRING, monthinfo STRING, dayinfo STRING)
   ROW FORMAT DELIMITED
   FIELDS TERMINATED BY '\t'
   stored as orc
   location '/user/hive/warehouse/itcast_dwm.db/class_attendance_dwm'
   TBLPROPERTIES ('orc.compress'='SNAPPY');
   
   --内存不足,执行以下命令
   drop table itcast_dwm.class_attendance_dwm;
   CREATE TABLE IF NOT EXISTS itcast_dwm.class_attendance_dwm (
       dateinfo        String        comment '日期',
       class_id          int           comment '班级id',
       morning_att_count       String         comment '上午出勤人数',
       afternoon_att_count      String        comment '下午出勤人数',
       evening_att_count       String        comment '晚自习出勤人数',
       morning_late_count       String         comment '上午迟到人数',
       afternoon_late_count      String        comment '下午迟到人数',
     evening_late_count       String        comment '晚自习迟到人数')
   comment '学生出勤(正常出勤和迟到)数据'
 PARTITIONED BY (yearinfo STRING, monthinfo STRING, dayinfo STRING)
   ROW FORMAT DELIMITED
   FIELDS TERMINATED BY '\t'
   location '/user/hive/warehouse/itcast_dwm.db/class_attendance_dwm';
  • 属性配置
      --本地模式
      set hive.exec.mode.local.auto=true;
      --分区
      SET hive.exec.dynamic.partition=true;
      SET hive.exec.dynamic.partition.mode=nonstrict;
      set hive.exec.max.dynamic.partitions.pernode=10000;
      set hive.exec.max.dynamic.partitions=100000;
      set hive.exec.max.created.files=150000;
      --hive压缩
      set hive.exec.compress.intermediate=true;
      set hive.exec.compress.output=true;
      --写入时压缩生效
      set hive.exec.orc.compression.strategy=COMPRESSION;
      --分桶
      set hive.enforce.bucketing=true;
      set hive.enforce.sorting=true;
      set hive.optimize.bucketmapjoin = true;
      set hive.auto.convert.sortmerge.join=true;
      set hive.auto.convert.sortmerge.join.noconditionaltask=true;
      --并行执行
      set hive.exec.parallel=false;
      set hive.exec.parallel.thread.number=8;
      --矢量化查询
      set hive.vectorized.execution.enabled=true;
      --关联优化器
      set hive.optimize.correlation=true;
      --读取零拷贝
      set hive.exec.orc.zerocopy=true;
      --join数据倾斜
      set hive.optimize.skewjoin=false;
      -- set hive.skewjoin.key=100000;
      set hive.optimize.skewjoin.compiletime=false;
      -- group倾斜
      set hive.groupby.skewindata=false;
      --分析优化器
      ANALYZE TABLE itcast_dwm.student_attendance_dwm partition(yearinfo, monthinfo, dayinfo) COMPUTE STATISTICS;
    ANALYZE TABLE itcast_dwm.student_attendance_dwm partition(yearinfo, monthinfo, dayinfo) COMPUTE    STATISTICS FOR COLUMNS;
      set hive.cbo.enable=true;
    set hive.stats.autogather=true;
      set hive.compute.query.using.stats=true;
      set hive.stats.fetch.column.stats=true;
      set hive.stats.fetch.partition.stats=true;
  • 实现班级状态信息表

    INSERT INTO itcast_dwm.class_attendance_dwm PARTITION (yearinfo, monthinfo, dayinfo)
    SELECT
        stu.dateinfo,
        stu.class_id,
        count(DISTINCT
            case WHEN (stu.morning_att='0' or stu.morning_att='1') THEN stu.student_id ELSE NULL END
            ) morning_att_count,
        count(DISTINCT
            case WHEN (stu.afternoon_att ='0' or stu.afternoon_att='1') THEN stu.student_id ELSE NULL END
            ) afternoon_att_count,
        count(DISTINCT
            case WHEN (stu.evening_att ='0' or stu.evening_att='1') THEN stu.student_id ELSE NULL END
            ) evening_att_count,
        count(DISTINCT
            case WHEN (stu.morning_att='1') THEN stu.student_id ELSE NULL END
            ) morning_late_count,
        count(DISTINCT
            case WHEN (stu.afternoon_att='1') THEN stu.student_id ELSE NULL END
            ) afternoon_late_count,
        count(DISTINCT
          case WHEN (stu.evening_att='1') THEN stu.student_id ELSE NULL END
            ) evening_late_count,
        stu.yearinfo,stu.monthinfo,stu.dayinfo
        from itcast_dwm.student_attendance_dwm stu
        where stu.student_id is not null
    GROUP BY stu.class_id,stu.yearinfo,stu.monthinfo,stu.dayinfo,stu.dateinfo;
    
  • 小结

    • 实现DWM层出勤状态表的构建

知识点11:数仓实现:DWM层请假

  • 目标:实现DWM层请假状态表的构建

  • 实施

    • 分析

      • ODS:学员请假信息表

        班级id		学员id			请假开始时间		请假结束时间			是否合法
        001				1				12:00:00		18:00:00			0
        001				2				12:00:00		18:00:00			1
        
      • DWM:班级请假人数报表

        时间		班级id		上午请假人数		下午请假人数		晚上请假人数
        
        • 每个时间段请假人数
          • 请假开始时间早于上课时间
          • 请假结束时间晚于下课时间
    • 实现

      • 建表

        drop table itcast_dwm.class_leave_dwm;
        CREATE TABLE IF NOT EXISTS itcast_dwm.class_leave_dwm (
            dateinfo      String        comment '日期',
            class_id        int           comment '班级id',
            morning_leave_count       String       comment '上午请假人数',
            afternoon_leave_count    String        comment '下午请假人数',
            evening_leave_count       String        comment '晚自习请假人数')
        comment '班级请假数据统计'
        PARTITIONED BY (yearinfo STRING, monthinfo STRING, dayinfo STRING)
        ROW FORMAT DELIMITED 
        FIELDS TERMINATED BY '\t'
        stored as orc
        location '/user/hive/warehouse/itcast_dwm.db/class_leave_dwm'
        TBLPROPERTIES ('orc.compress'='SNAPPY');
        
      • 实现

        INSERT INTO itcast_dwm.class_leave_dwm PARTITION (yearinfo, monthinfo, dayinfo)
        SELECT
            morning.dateinfo,
            morning.class_id,
            morning.morning_leave_count,
            afternoon.afternoon_leave_count,
            evening.evening_leave_count,
            substr(morning.dateinfo, 1, 4) yearinfo,
            substr(morning.dateinfo, 6, 2) monthinfo,
            substr(morning.dateinfo, 9, 2) dayinfo
        from
        --统计上午请假的人数
        (
            SELECT
                cource.class_date as dateinfo,--上课日期
                cource.class_id,--班级id
                count(DISTINCT leave.student_id) as morning_leave_count--请假的人数
            FROM
                itcast_dimen.course_table_upload_detail_dimen cource,--排课表
                itcast_ods.student_leave_apply_ods leave,--请假表
                itcast_dimen.class_time_dimen ti--作息时间
            --过滤出所有合法的请假的信息
            WHERE cource.class_id=leave.class_id
                and cource.class_id=ti.class_id
                --这天的课程非空并且不是开班典礼
                and cource.content is NOT NULL and cource.content != '开班典礼'
                --保证是有效的作息时间
                AND ti.use_begin_date <= cource.class_date
                AND ti.use_end_date >= cource.class_date
                -- 请假开始时间  <= 上课开始时间  <= 请假结束时间
                AND leave.begin_time <= concat(cource.class_date, ' ', ti.morning_begin_time)
                AND concat(cource.class_date, ' ', ti.morning_begin_time) <= leave.end_time
                --请假是否有效
                AND leave.audit_state=1   --审批通过
                AND leave.cancel_state=0  --没有撤销
                AND leave.valid_state=1   --有效请假
            GROUP BY cource.class_id, cource.class_date
        ) morning
        FULL JOIN
        (
            SELECT
                cource.class_date as dateinfo,
                cource.class_id,
                count(DISTINCT leave.student_id) as afternoon_leave_count
            FROM
                itcast_dimen.course_table_upload_detail_dimen cource,
                itcast_ods.student_leave_apply_ods leave,
                itcast_dimen.class_time_dimen ti
            WHERE cource.class_id=leave.class_id
                and cource.class_id=ti.class_id
                and cource.content is NOT NULL and cource.content != '开班典礼'
                --作息时间匹配
                AND ti.use_begin_date <= cource.class_date
                AND ti.use_end_date >= cource.class_date
                -- 请假开始时间  <= 上课开始时间  <= 请假结束时间
                AND leave.begin_time <= concat(cource.class_date, ' ', ti.afternoon_begin_time)
                AND concat(cource.class_date, ' ', ti.afternoon_begin_time) <= leave.end_time
                --请假是否有效
                AND leave.audit_state=1
                AND leave.cancel_state=0
                AND leave.valid_state=1
            GROUP BY cource.class_id, cource.class_date
        ) afternoon on morning.class_id=afternoon.class_id AND morning.dateinfo=afternoon.dateinfo
        FULL JOIN
        (
            SELECT
                cource.class_date as dateinfo,
                cource.class_id,
                count(DISTINCT leave.student_id) as evening_leave_count
            FROM
                itcast_dimen.course_table_upload_detail_dimen cource,
                itcast_ods.student_leave_apply_ods leave,
                itcast_dimen.class_time_dimen ti
            WHERE cource.class_id=leave.class_id
                and cource.class_id=ti.class_id
                and cource.content is NOT NULL and cource.content != '开班典礼'
                --作息时间匹配
                AND ti.use_begin_date <= cource.class_date
                AND ti.use_end_date >= cource.class_date
                -- 请假开始时间  <= 上课开始时间  <= 请假结束时间
                AND leave.begin_time <= concat(cource.class_date, ' ', ti.evening_begin_time)
                AND concat(cource.class_date, ' ', ti.evening_begin_time) <= leave.end_time
                --请假是否有效
                AND leave.audit_state=1
                AND leave.cancel_state=0
                AND leave.valid_state=1
            GROUP BY cource.class_id, cource.class_date
        ) evening on morning.dateinfo=evening.dateinfo AND morning.class_id=evening.class_id;
        
  • 小结

    • 实现DWM层请假状态表的构建

知识点12:数仓实现:DWM层旷课

  • 目标实现DWM层旷课状态表的构建

  • 实施

    • 分析

      • DWM

        • 班级出勤状态表

          时间 班级id	上午出勤人数	上午迟到人数  下午出勤人数 下午迟到人数  晚上出勤人数	晚上迟到人数
          
        • 班级请假人数表

          时间		班级id		上午请假人数		下午请假人数		晚上请假人数
          
        • DIM:班级总人数表

          班级id		总人数
          
      • DWM:班级旷课信息表

        时间		班级		上午旷课人数		下午旷课人数		晚上旷课人数
        
    • 实现

      • 建表

        drop table itcast_dwm.class_truant_dwm;
        CREATE TABLE IF NOT EXISTS itcast_dwm.class_truant_dwm (
            dateinfo      String        comment '日期',
            class_id        int           comment '班级id',
            morning_truant_count       String          comment '上午旷课人数',
            afternoon_truant_count   String        comment '下午旷课人数',
            evening_truant_count       String        comment '晚自习旷课人数')
        comment '班级请假数据统计'
        PARTITIONED BY (yearinfo STRING, monthinfo STRING, dayinfo STRING)
        ROW FORMAT DELIMITED 
        FIELDS TERMINATED BY '\t'
        stored as orc
        location '/user/hive/warehouse/itcast_dwm.db/class_truant_dwm'
        TBLPROPERTIES ('orc.compress'='SNAPPY');
        
      • 实现

        INSERT INTO itcast_dwm.class_truant_dwm PARTITION (yearinfo, monthinfo, dayinfo)
        SELECT
            course.class_date dateinfo,
            course.class_id,
            nvl(ct.studying_student_count, 0) - nvl(att.morning_att_count, 0) - nvl(leave.morning_leave_count, 0) morning_truant_count,
            nvl(ct.studying_student_count, 0) - nvl(att.afternoon_att_count, 0) - nvl(leave.afternoon_leave_count, 0) afternoon_truant_count,
            nvl(ct.studying_student_count, 0) - nvl(att.evening_att_count, 0) - nvl(leave.evening_leave_count, 0) evening_truant_count,
            substr(course.class_date, 1,4) yearinfo,
            substr(course.class_date, 6,2) monthinfo,
            substr(course.class_date, 9,2) dayinfo
        from itcast_dimen.course_table_upload_detail_dimen course
            LEFT JOIN itcast_dwm.class_attendance_dwm att on course.class_id = att.class_id and att.dateinfo = course.class_date
            LEFT JOIN itcast_dwm.class_leave_dwm leave on course.class_id = leave.class_id AND course.class_date = leave.dateinfo
            LEFT JOIN itcast_dimen.class_studying_student_count_dimen ct on ct.class_id = course.class_id and course.class_date=ct.studying_date
        WHERE ct.studying_student_count IS NOT NULL AND course.content IS NOT NULL AND course.content != '开班典礼';
        
  • 小结

    • 实现DWM层旷课状态表的构建

知识点13:数仓实现:DWS层

  • 目标:实现DWS每日班级出勤情况表的构建

  • 实施

    • 分析

      • DWM层

        • 班级出勤信息表

          时间	班级id	上午出勤	上午迟到	下午出勤	下午迟到		晚上出勤	晚上迟到
          
        • 班级请假信息表

          时间	班级id	上午请假人数	下午请假人数	晚上请假人数
          
        • 班级旷课信息表

          时间	班级id	上午旷课人数	下午旷课人数	晚上旷课人数
          
        • 班级总人数

          班级id	班级总人数
          
      • DWS:基于天维度得到每天三个时间段每个时间段的8个指标

        时间		班级		上午出勤人数	上午出勤率	下午出勤人数	下午出勤率	晚上出勤人数	晚上出勤率
        
    • 实现

      • 建表

        drop table itcast_dws.class_attendance_dws;
        CREATE TABLE IF NOT EXISTS itcast_dws.class_attendance_dws (
            dateinfo      String        comment '日期',
            class_id        int           comment '班级id',
           studying_student_count int  comment '在读班级人数',
            morning_att_count       String         comment '上午出勤人数',
           morning_att_ratio       String         comment '上午出勤率',
            afternoon_att_count      String        comment '下午出勤人数',
           afternoon_att_ratio      String        comment '下午出勤率',
            evening_att_count       String        comment '晚自习出勤人数',
           evening_att_ratio       String        comment '晚自习出勤率',
           morning_late_count       String        comment '上午迟到人数',
           morning_late_ratio       String        comment '上午迟到率',
            afternoon_late_count     String        comment '下午迟到人数',
           afternoon_late_ratio     String        comment '下午迟到率',
            evening_late_count       String        comment '晚自习迟到人数',
           evening_late_ratio       String        comment '晚自习迟到率',
           morning_leave_count       String       comment '上午请假人数',
           morning_leave_ratio       String       comment '上午请假率',
            afternoon_leave_count    String        comment '下午请假人数',
           afternoon_leave_ratio    String        comment '下午请假率',
            evening_leave_count       String        comment '晚自习请假人数',
           evening_leave_ratio       String        comment '晚自习请假率',
            morning_truant_count       String          comment '上午旷课人数',
           morning_truant_ratio       String          comment '上午旷课率',
            afternoon_truant_count   String        comment '下午旷课人数',
           afternoon_truant_ratio   String        comment '下午旷课率',
            evening_truant_count       String        comment '晚自习旷课人数',
           evening_truant_ratio       String        comment '晚自习旷课率')
        comment '班级请假数据统计'
        PARTITIONED BY (yearinfo STRING, monthinfo STRING, dayinfo STRING)
        ROW FORMAT DELIMITED 
        FIELDS TERMINATED BY '\t'
        stored as orc
        location '/user/hive/warehouse/itcast_dws.db/class_attendance_dws'
        TBLPROPERTIES ('orc.compress'='SNAPPY');
        
        --内存不足
        drop table itcast_dws.class_attendance_dws;
        CREATE TABLE IF NOT EXISTS itcast_dws.class_attendance_dws (
            dateinfo      String        comment '日期',
            class_id        int           comment '班级id',
           studying_student_count int  comment '在读班级人数',
            morning_att_count       String         comment '上午出勤人数',
           morning_att_ratio       String         comment '上午出勤率',
            afternoon_att_count      String        comment '下午出勤人数',
           afternoon_att_ratio      String        comment '下午出勤率',
            evening_att_count       String        comment '晚自习出勤人数',
           evening_att_ratio       String        comment '晚自习出勤率',
           morning_late_count       String        comment '上午迟到人数',
           morning_late_ratio       String        comment '上午迟到率',
            afternoon_late_count     String        comment '下午迟到人数',
           afternoon_late_ratio     String        comment '下午迟到率',
            evening_late_count       String        comment '晚自习迟到人数',
           evening_late_ratio       String        comment '晚自习迟到率',
           morning_leave_count       String       comment '上午请假人数',
           morning_leave_ratio       String       comment '上午请假率',
            afternoon_leave_count    String        comment '下午请假人数',
           afternoon_leave_ratio    String        comment '下午请假率',
            evening_leave_count       String        comment '晚自习请假人数',
           evening_leave_ratio       String        comment '晚自习请假率',
            morning_truant_count       String          comment '上午旷课人数',
           morning_truant_ratio       String          comment '上午旷课率',
            afternoon_truant_count   String        comment '下午旷课人数',
           afternoon_truant_ratio   String        comment '下午旷课率',
            evening_truant_count       String        comment '晚自习旷课人数',
           evening_truant_ratio       String        comment '晚自习旷课率')
        comment '班级请假数据统计'
        PARTITIONED BY (yearinfo STRING, monthinfo STRING, dayinfo STRING)
        ROW FORMAT DELIMITED 
        FIELDS TERMINATED BY '\t'
        location '/user/hive/warehouse/itcast_dws.db/class_attendance_dws';
        
      • 实现

        INSERT INTO itcast_dws.class_attendance_dws PARTITION (yearinfo, monthinfo, dayinfo)
        SELECT 
            course.class_date dateinfo, 
            course.class_id,
            total.studying_student_count,
            --统计出勤情况
            att.morning_att_count,
            cast((att.morning_att_count / total.studying_student_count) * 100 as DECIMAL(8,2)) morning_att_ratio, 
            att.afternoon_att_count,
            cast((att.afternoon_att_count / total.studying_student_count) * 100 as DECIMAL(8,2))  afternoon_att_ratio, 
            att.evening_att_count,
            cast((att.evening_att_count / total.studying_student_count) * 100 as DECIMAL(8,2)) evening_att_ratio, 
            --统计迟到情况
            att.morning_late_count,
            cast((att.morning_late_count / total.studying_student_count) * 100 as DECIMAL(8,2))  morning_late_ratio, 
            att.afternoon_late_count,
            cast((att.afternoon_late_count / total.studying_student_count) * 100 as DECIMAL(8,2))  afternoon_late_ratio, 
            att.evening_late_count,
            cast((att.evening_late_count / total.studying_student_count) * 100 as DECIMAL(8,2)) evening_late_ratio,
            --统计请假情况
            lev.morning_leave_count,
            cast((lev.morning_leave_count / total.studying_student_count) * 100 as DECIMAL(8,2))  morning_leave_ratio, 
            lev.afternoon_leave_count,
            cast((lev.afternoon_leave_count / total.studying_student_count) * 100 as DECIMAL(8,2)) afternoon_leave_ratio, 
            lev.evening_leave_count,
            cast((lev.evening_leave_count / total.studying_student_count) * 100 as DECIMAL(8,2)) evening_leave_ratio, 
            --统计旷课情况
            tru.morning_truant_count,
            cast((tru.morning_truant_count / total.studying_student_count) * 100 as DECIMAL(8,2)) morning_truant_ratio, 
            tru.afternoon_truant_count,
            cast((tru.afternoon_truant_count / total.studying_student_count) * 100 as DECIMAL(8,2)) afternoon_truant_ratio, 
            tru.evening_truant_count,
            cast((tru.evening_truant_count / total.studying_student_count) * 100 as DECIMAL(8,2)) evening_truant_ratio, 
            --时间维度
            substr(course.class_date, 1,4) yearinfo,
            substr(course.class_date, 6,2) monthinfo,
            substr(course.class_date, 9,2) dayinfo
        from itcast_dimen.course_table_upload_detail_dimen course
            LEFT JOIN itcast_dimen.class_studying_student_count_dimen total on course.class_date=total.studying_date AND course.class_id = total.class_id
            LEFT JOIN itcast_dwm.class_attendance_dwm att on course.class_date=att.dateinfo AND course.class_id = att.class_id
            LEFT JOIN itcast_dwm.class_leave_dwm lev on course.class_id=lev.class_id AND course.class_date=lev.dateinfo
            LEFT JOIN itcast_dwm.class_truant_dwm tru on course.class_id=tru.class_id AND course.class_date=tru.dateinfo
        WHERE course.content IS NOT NULL AND course.content != '开班典礼' AND total.studying_student_count IS NOT NULL;
        
  • 小结

    • 实现DWS层的构建

知识点14:数仓实现:APP层

  • 目标实现APP层的构建

  • 实施

    • 分析

      • 基于天维度下每个班级的指标,得到月维度以及年维度下的指标
    • 实现

      • 建表

        drop table itcast_app.class_attendance_app;
        CREATE TABLE IF NOT EXISTS itcast_app.class_attendance_app (
            dateinfo      String        comment '日期',
            class_id        int           comment '班级id',
           studying_student_count int  comment '在读班级人数',
            morning_att_count       String         comment '上午出勤人数',
           morning_att_ratio       String         comment '上午出勤率',
            afternoon_att_count      String        comment '下午出勤人数',
           afternoon_att_ratio      String        comment '下午出勤率',
            evening_att_count       String        comment '晚自习出勤人数',
           evening_att_ratio       String        comment '晚自习出勤率',
           morning_late_count       String        comment '上午迟到人数',
           morning_late_ratio       String        comment '上午迟到率',
            afternoon_late_count     String        comment '下午迟到人数',
           afternoon_late_ratio     String        comment '下午迟到率',
            evening_late_count       String        comment '晚自习迟到人数',
           evening_late_ratio       String        comment '晚自习迟到率',
           morning_leave_count       String       comment '上午请假人数',
           morning_leave_ratio       String       comment '上午请假率',
            afternoon_leave_count    String        comment '下午请假人数',
           afternoon_leave_ratio    String        comment '下午请假率',
            evening_leave_count       String        comment '晚自习请假人数',
           evening_leave_ratio       String        comment '晚自习请假率',
            morning_truant_count       String          comment '上午旷课人数',
           morning_truant_ratio       String          comment '上午旷课率',
            afternoon_truant_count   String        comment '下午旷课人数',
           afternoon_truant_ratio   String        comment '下午旷课率',
            evening_truant_count       String        comment '晚自习旷课人数',
           evening_truant_ratio       String        comment '晚自习旷课率',
           time_type            STRING       COMMENT '聚合时间类型:1、按小时聚合;2、按天聚合;3、按周聚合;4、按月聚合;5、按年聚合。')
        comment '班级请假数据统计'
        PARTITIONED BY (yearinfo STRING, monthinfo STRING, dayinfo STRING)
        ROW FORMAT DELIMITED 
        FIELDS TERMINATED BY '\t'
        stored as orc
        location '/user/hive/warehouse/itcast_app.db/class_attendance_app'
        TBLPROPERTIES ('orc.compress'='SNAPPY');
        
        
        --内存不足
        drop table itcast_app.class_attendance_app;
        CREATE TABLE IF NOT EXISTS itcast_app.class_attendance_app (
            dateinfo      String        comment '日期',
            class_id        int           comment '班级id',
           studying_student_count int  comment '在读班级人数',
            morning_att_count       String         comment '上午出勤人数',
           morning_att_ratio       String         comment '上午出勤率',
            afternoon_att_count      String        comment '下午出勤人数',
           afternoon_att_ratio      String        comment '下午出勤率',
            evening_att_count       String        comment '晚自习出勤人数',
           evening_att_ratio       String        comment '晚自习出勤率',
           morning_late_count       String        comment '上午迟到人数',
           morning_late_ratio       String        comment '上午迟到率',
            afternoon_late_count     String        comment '下午迟到人数',
           afternoon_late_ratio     String        comment '下午迟到率',
            evening_late_count       String        comment '晚自习迟到人数',
           evening_late_ratio       String        comment '晚自习迟到率',
           morning_leave_count       String       comment '上午请假人数',
           morning_leave_ratio       String       comment '上午请假率',
            afternoon_leave_count    String        comment '下午请假人数',
           afternoon_leave_ratio    String        comment '下午请假率',
            evening_leave_count       String        comment '晚自习请假人数',
           evening_leave_ratio       String        comment '晚自习请假率',
            morning_truant_count       String          comment '上午旷课人数',
           morning_truant_ratio       String          comment '上午旷课率',
            afternoon_truant_count   String        comment '下午旷课人数',
           afternoon_truant_ratio   String        comment '下午旷课率',
            evening_truant_count       String        comment '晚自习旷课人数',
           evening_truant_ratio       String        comment '晚自习旷课率',
           time_type            STRING       COMMENT '聚合时间类型:1、按小时聚合;2、按天聚合;3、按周聚合;4、按月聚合;5、按年聚合。')
        comment '班级请假数据统计'
        PARTITIONED BY (yearinfo STRING, monthinfo STRING, dayinfo STRING)
        ROW FORMAT DELIMITED 
        FIELDS TERMINATED BY '\t'
        location '/user/hive/warehouse/itcast_app.db/class_attendance_app';
        
      • 实现

        • INSERT OVERWRITE TABLE itcast_app.class_attendance_app partition (yearinfo,  monthinfo, dayinfo) select  
               dateinfo,  
               class_id,  
               studying_student_count,  
               morning_att_count,  
               morning_att_ratio,  
               afternoon_att_count,  
               afternoon_att_ratio,  
               evening_att_count,  
               evening_att_ratio,  
               morning_late_count,  
               morning_late_ratio,  
               afternoon_late_count,  
               afternoon_late_ratio,  
               evening_late_count,  
               evening_late_ratio,  
               morning_leave_count,  
               morning_leave_ratio,  
               afternoon_leave_count,  
               afternoon_leave_ratio,  
               evening_leave_count,  
               evening_leave_ratio,  
               morning_truant_count,  
               morning_truant_ratio,  
               afternoon_truant_count,  
               afternoon_truant_ratio,  
               evening_truant_count,
               evening_truant_ratio,  
               '2',  
               yearinfo,  
               monthinfo,  
               dayinfo  
          from itcast_dws.class_attendance_dws;
          
        • INSERT INTO itcast_app.class_attendance_app PARTITION(yearinfo, monthinfo, dayinfo)
          SELECT
                  concat_ws('-', yearinfo, monthinfo),
                  class_id,
                  sum(studying_student_count),
                  sum(morning_att_count),
                  cast((sum(morning_att_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) morning_att_ratio,
                  sum(afternoon_att_count),
                 cast((sum(afternoon_att_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) afternoon_att_ratio,
                  sum(evening_att_count),
                 cast((sum(evening_att_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) evening_att_ratio,
                  sum(morning_late_count),
                 cast((sum(morning_late_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) morning_late_ratio,
                  sum(afternoon_late_count),
                 cast((sum(afternoon_late_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) afternoon_late_ratio,
                  sum(evening_late_count),
                 cast((sum(evening_late_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) evening_late_ratio,
                  sum(morning_leave_count),
                 cast((sum(morning_leave_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) morning_leave_ratio,
                  sum(afternoon_leave_count),
                 cast((sum(afternoon_leave_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) afternoon_leave_ratio,
                  sum(evening_leave_count),
                 cast((sum(evening_leave_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) evening_leave_ratio,
                  sum(morning_truant_count),
                 cast((sum(morning_truant_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) morning_truant_ratio,
                  sum(afternoon_truant_count),
                 cast((sum(afternoon_truant_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) afternoon_truant_ratio,
                  sum(evening_truant_count),
                 cast((sum(evening_truant_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) evening_truant_ratio,
                 '4',
                 yearinfo,
                 monthinfo,
                 '-1' as dayinfo
          from itcast_dws.class_attendance_dws
          --每个月每个班级
          GROUP BY yearinfo, monthinfo, class_id;
          
        • INSERT INTO itcast_app.class_attendance_app PARTITION(yearinfo, monthinfo, dayinfo)
          SELECT
                  yearinfo,
                  class_id,
                  sum(studying_student_count),
                  sum(morning_att_count),
                  cast((sum(morning_att_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) morning_att_ratio,
                  sum(afternoon_att_count),
                 cast((sum(afternoon_att_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) afternoon_att_ratio,
                  sum(evening_att_count),
                 cast((sum(evening_att_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) evening_att_ratio,
                  sum(morning_late_count),
                 cast((sum(morning_late_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) morning_late_ratio,
                  sum(afternoon_late_count),
                 cast((sum(afternoon_late_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) afternoon_late_ratio,
                  sum(evening_late_count),
                 cast((sum(evening_late_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) evening_late_ratio,
                  sum(morning_leave_count),
                 cast((sum(morning_leave_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) morning_leave_ratio,
                  sum(afternoon_leave_count),
                 cast((sum(afternoon_leave_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) afternoon_leave_ratio,
                  sum(evening_leave_count),
                 cast((sum(evening_leave_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) evening_leave_ratio,
                  sum(morning_truant_count),
                 cast((sum(morning_truant_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) morning_truant_ratio,
                  sum(afternoon_truant_count),
                 cast((sum(afternoon_truant_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) afternoon_truant_ratio,
                  sum(evening_truant_count),
                 cast((sum(evening_truant_count) / sum(studying_student_count)) * 100 as decimal(8, 2)) evening_truant_ratio,
                 '5',
                 yearinfo,
                 '-1'  as monthinfo,
                 '-1' as dayinfo
          from itcast_dws.class_attendance_dws
          GROUP BY yearinfo,class_id;
          
  • 小结

    • 实现APP层的构建

知识点15:数仓实现:导出结果

  • 目标实现结果的导出

  • 实施

    • 建表

      use scrm_bi;
      drop table class_attendance_app;
      CREATE TABLE IF NOT EXISTS class_attendance_app (
          class_id              int         comment '班级id',
         studying_student_count     float       comment '在读班级人数',
          morning_att_count       float        comment '上午出勤人数',
         morning_att_ratio       float          comment '上午出勤率',
          afternoon_att_count       float            comment '下午出勤人数',
         afternoon_att_ratio       float        comment '下午出勤率',
          evening_att_count       float            comment '晚自习出勤人数',
         evening_att_ratio       float        comment '晚自习出勤率',
         morning_late_count      float        comment '上午迟到人数',
         morning_late_ratio      float          comment '上午迟到率',
          afternoon_late_count   float            comment '下午迟到人数',
         afternoon_late_ratio   float        comment '下午迟到率',
          evening_late_count      float            comment '晚自习迟到人数',
         evening_late_ratio      float        comment '晚自习迟到率',
         morning_leave_count     float        comment '上午请假人数',
         morning_leave_ratio     float          comment '上午请假率',
          afternoon_leave_count  float            comment '下午请假人数',
         afternoon_leave_ratio  float        comment '下午请假率',
          evening_leave_count     float            comment '晚自习请假人数',
         evening_leave_ratio     float        comment '晚自习请假率',
          morning_truant_count    float        comment '上午旷课人数',
         morning_truant_ratio    float          comment '上午旷课率',
          afternoon_truant_count float            comment '下午旷课人数',
         afternoon_truant_ratio float        comment '下午旷课率',
          evening_truant_count    float            comment '晚自习旷课人数',
         evening_truant_ratio    float        comment '晚自习旷课率',
         time_type            varchar(8)    COMMENT '聚合时间类型:1、按小时聚合;2、按天聚合;3、按周聚合;4、按月聚合;5、按年聚合。',
         yearinfo            varchar(8)    COMMENT '年',
         monthinfo            varchar(8)    COMMENT '月',
         dayinfo            varchar(8)    COMMENT '日'
      )
      comment '班级请假数据统计';
      
    • 实现

      sqoop export \
      --connect "jdbc:mysql://node3:3306/scrm_bi?useUnicode=true&characterEncoding=utf-8" \
      --username root \
      --password 123456 \
      --driver com.mysql.jdbc.Driver \
      --table class_attendance_app \
      --hcatalog-database itcast_app \
      --hcatalog-table class_attendance_app \
      -m 1
      
  • 小结

    • 实现结果的导出

知识点16:练习:有效线索主题

  • 目标自己动手实现有效线索主题的分析开发

  • 实施

    • step1:了解线索主题的业务需求

      • 需求:统计不同维度下的有效线索的个数
      • 指标:统计有效线索的个数
        • 怎么界定这个线索是一个有效线索
      • 维度:时间、新老学员、线上线下
    • step2:了解线索主题的数据来源

      • customer_clue:线索信息表,记录了每一条线索的信息

        • 用于对线索的id进行统计,统计有效线索个数
        • 时间
        • 新老学员
      • customer_relationship:用于提供线上线下维度

        • orgin_type:线上线下
      • customer_appeal:线索申诉表

          `id` int COMMENT 'customer_appeal_id',
          `customer_relationship_first_id` int COMMENT '第一条客户关系id',
          `employee_id` int COMMENT '申诉人',
          `employee_name` STRING COMMENT '申诉人姓名',
          `employee_department_id` int COMMENT '申诉人部门',
          `employee_tdepart_id` int COMMENT '申诉人所属部门',
          `appeal_status` int COMMENT '申诉状态,0:待稽核 1:无效 2:有效',
          `audit_id` int COMMENT '稽核人id',
          `audit_name` STRING COMMENT '稽核人姓名',
          `audit_department_id` int COMMENT '稽核人所在部门',
          `audit_department_name` STRING COMMENT '稽核人部门名称',
          `audit_date_time` STRING COMMENT '稽核时间',
          `create_date_time` STRING COMMENT '创建时间(申诉时间)',
          `update_date_time` STRING COMMENT '更新时间',
          `deleted` STRING COMMENT '删除标志位',
          `tenant` int COMMENT '租户id') 
        
        
        • 用于提供判断是否是一个有效线索

          where appeal_status != 1
          
    • step3:分析线索主题的数仓设计

    • step4:实现线索主题的数仓构建

 comment '下午旷课率',
        evening_truant_count    float            comment '晚自习旷课人数',
       evening_truant_ratio    float        comment '晚自习旷课率',
       time_type            varchar(8)    COMMENT '聚合时间类型:1、按小时聚合;2、按天聚合;3、按周聚合;4、按月聚合;5、按年聚合。',
       yearinfo            varchar(8)    COMMENT '年',
       monthinfo            varchar(8)    COMMENT '月',
       dayinfo            varchar(8)    COMMENT '日'
    )
    comment '班级请假数据统计';
  • 实现

    sqoop export \
    --connect "jdbc:mysql://node3:3306/scrm_bi?useUnicode=true&characterEncoding=utf-8" \
    --username root \
    --password 123456 \
    --driver com.mysql.jdbc.Driver \
    --table class_attendance_app \
    --hcatalog-database itcast_app \
    --hcatalog-table class_attendance_app \
    -m 1
    
  • 小结

    • 实现结果的导出

知识点16:练习:有效线索主题

  • 目标自己动手实现有效线索主题的分析开发

  • 实施

    • step1:了解线索主题的业务需求

      • 需求:统计不同维度下的有效线索的个数
      • 指标:统计有效线索的个数
        • 怎么界定这个线索是一个有效线索
      • 维度:时间、新老学员、线上线下
    • step2:了解线索主题的数据来源

      • customer_clue:线索信息表,记录了每一条线索的信息

        • 用于对线索的id进行统计,统计有效线索个数
        • 时间
        • 新老学员
      • customer_relationship:用于提供线上线下维度

        • orgin_type:线上线下
      • customer_appeal:线索申诉表

          `id` int COMMENT 'customer_appeal_id',
          `customer_relationship_first_id` int COMMENT '第一条客户关系id',
          `employee_id` int COMMENT '申诉人',
          `employee_name` STRING COMMENT '申诉人姓名',
          `employee_department_id` int COMMENT '申诉人部门',
          `employee_tdepart_id` int COMMENT '申诉人所属部门',
          `appeal_status` int COMMENT '申诉状态,0:待稽核 1:无效 2:有效',
          `audit_id` int COMMENT '稽核人id',
          `audit_name` STRING COMMENT '稽核人姓名',
          `audit_department_id` int COMMENT '稽核人所在部门',
          `audit_department_name` STRING COMMENT '稽核人部门名称',
          `audit_date_time` STRING COMMENT '稽核时间',
          `create_date_time` STRING COMMENT '创建时间(申诉时间)',
          `update_date_time` STRING COMMENT '更新时间',
          `deleted` STRING COMMENT '删除标志位',
          `tenant` int COMMENT '租户id') 
        
        
        • 用于提供判断是否是一个有效线索

          where appeal_status != 1
          
    • step3:分析线索主题的数仓设计

    • step4:实现线索主题的数仓构建

上一篇:SQL之树形查询结构设计


下一篇:第二章上机实践总结