图解HIVE累积型快照事实表

本文介绍了如何在数据仓库中处理事实表,特别是事务型和累积型快照事实表。通过行转多列的方法展示了订单状态表的转换,并详细展示了数据从ODS层到DWD层的同步过程,包括动态分区设置和数据更新策略。同时,文章涵盖了数据路径、SQL示例以及不同状态的时间字段和其意义。
摘要由CSDN通过智能技术生成

概述

  • 什么是事实表?
    每行数据代表一个业务事件,通常有很多外键(地区、用户…)
    业务事件可以是:下单、支付、退款、评价…
    业务事件有数字度量,如:数量、金额、次数…
    行数较多,列数较少
    每天很多新增

  • 事实表的分类

分类说明特点场景
事务型事实表以每个事务为单位数据只追加不修改一个订单支付
一笔订单退款
周期型快照事实表保留固定时间间隔的数据不会保留所有数据点赞数
累积型快照事实表跟踪业务事实的变化数据可修改订单状态
  • 本文以订单状态表为例

行转多列

1、按订单ID分组,聚合订单状态时间,转为MAP

SELECT
    order_id,
    STR_TO_MAP(CONCAT_WS(',',COLLECT_SET(CONCAT(order_status,'=',operation_time))),',','=') m
FROM
    ods_order_status
GROUP BY
    order_id

打印结果

+--------+----------------------------------------------------------+
|order_id|m                                                         |
+--------+----------------------------------------------------------+
|P2      |[end -> 2020-01-01 23:45:00, start -> 2020-01-01 22:45:00]|
|P3      |[start -> 2020-01-01 23:30:00]                            |
|P1      |[start -> 2020-01-01 08:00:00, end -> 2020-01-01 08:01:00]|
+--------+----------------------------------------------------------+

2、按Key获取MAP值

WITH
    t1 AS (
        SELECT
            order_id,
            STR_TO_MAP(CONCAT_WS(',',COLLECT_SET(CONCAT(order_status,'=',operation_time))),',','=') m
        FROM
            ods_order_status
        GROUP BY
            order_id
    )
SELECT
    order_id,
    m['start'] start_time,
    m['end'] end_time
FROM
    t1

打印结果

+--------+-------------------+-------------------+
|order_id|start_time         |end_time           |
+--------+-------------------+-------------------+
|P2      |2020-01-01 22:45:00|2020-01-01 23:45:00|
|P3      |2020-01-01 23:30:00|null               |
|P1      |2020-01-01 08:00:00|2020-01-01 08:01:00|
+--------+-------------------+-------------------+

数仓详细

数据路径

Sqoop
HIVE
HIVE
MySQL
HDFS
ODS
DWD
表名表名路径策略备注
ods_order订单表sqoop > hdfs > ods增量变化同步
create_timeoperate_time
此处省略
ods_order_status订单状态流水表sqoop > hdfs > ods增量同步
operate_time
dwd_order订单表ods > dwd未结束订单写到9999-12-31分区
结束订单按结束日期写到日期分区

代码

1、数据准备

-- 建库:e-commerce
DROP DATABASE IF EXISTS ec CASCADE;
CREATE DATABASE ec LOCATION '/ec';
USE ec;
-- 建表:原始层,订单状态表
DROP TABLE IF EXISTS ec.ods_order_status;
CREATE TABLE ec.ods_order_status (
    order_id STRING,
    order_status STRING,
    operation_time STRING)
PARTITIONED BY (ymd STRING)
LOCATION '/ec/ods_order_status';
-- 建表:明细层,订单(累积型快照事实)表
DROP TABLE IF EXISTS ec.dwd_order;
CREATE TABLE ec.dwd_order (
    order_id STRING,
    start_time STRING,
    end_time STRING)
PARTITIONED BY (ymd STRING)
LOCATION '/ec/dwd_order';
-- 造数据,写到原始层
INSERT INTO TABLE ec.ods_order_status PARTITION(ymd='2020-01-01') VALUES
("P1","start","2020-01-01 08:00:00"),
("P1","end","2020-01-01 08:01:00"),
("P2","start","2020-01-01 22:45:00"),
("P3","start","2020-01-01 23:30:00");
INSERT INTO TABLE ec.ods_order_status PARTITION(ymd='2020-01-02') VALUES
("P3","end","2020-01-02 00:15:00"),
("P4","start","2020-01-02 06:30:00");

2、设置动态分区

-- 开启动态分区功能
SET hive.exec.dynamic.partition=true;
-- 设置动态分区为非严格模式
SET hive.exec.dynamic.partition.mode=nonstrict;

3、第一天数据写入

数据查询
WITH
    t1 AS(
        SELECT
            order_id,
            STR_TO_MAP(CONCAT_WS(',',COLLECT_SET(CONCAT(order_status,'=',operation_time))),',','=') m
        FROM ec.ods_order_status
        WHERE ymd='2020-01-01'
        GROUP BY order_id
    )
SELECT
    order_id,
    m['start'] start_time,
    m['end'] end_time,
    CASE
        WHEN m['end'] IS NOT NULL THEN '2020-01-01'
        ELSE '9999-12-31'
    END ymd
FROM t1;

查询结果

数据写入

注意:语法要求WITH写在INSERT前面

WITH
    t1 AS(
        SELECT
            order_id,
            STR_TO_MAP(CONCAT_WS(',',COLLECT_SET(CONCAT(order_status,'=',operation_time))),',','=') m
        FROM ec.ods_order_status
        WHERE ymd='2020-01-01'
        GROUP BY order_id
    )
INSERT OVERWRITE TABLE ec.dwd_order PARTITION(ymd)
SELECT
    order_id,
    m['start'] start_time,
    m['end'] end_time,
    CASE
        WHEN m['end'] IS NOT NULL THEN '2020-01-01'
        ELSE '9999-12-31'
    END ymd
FROM t1;

写入后结果

4、第二天数据写入

数据查询
WITH
    t1 AS(
        SELECT
            order_id,
            STR_TO_MAP(CONCAT_WS(',',COLLECT_SET(CONCAT(order_status,'=',operation_time))),',','=')m
        FROM ec.ods_order_status
        WHERE ymd='2020-01-02'
        GROUP BY order_id
    ),
    new AS(
    SELECT
        order_id,
        m['start'] start_time,
        m['end'] end_time,
        CASE
            WHEN m['end'] IS NOT NULL THEN '2020-01-02'
            ELSE '9999-12-31'
        END ymd
    FROM
        t1
    ),
    old AS (SELECT * FROM ec.dwd_order WHERE ymd='9999-12-31')
SELECT
    NVL(new.order_id,old.order_id) order_id,
    NVL(new.start_time,old.start_time) start_time,
    NVL(new.end_time,old.end_time) end_time,
    NVL(new.ymd,old.ymd) ymd
FROM new
FULL OUTER JOIN old
ON new.order_id=old.order_id;

查询结果

数据写入

注意:语法要求WITH写在INSERT前面

WITH
    t1 AS(
        SELECT
            order_id,
            STR_TO_MAP(CONCAT_WS(',',COLLECT_SET(CONCAT(order_status,'=',operation_time))),',','=')m
        FROM ec.ods_order_status
        WHERE ymd='2020-01-02'
        GROUP BY order_id
    ),
    new AS(
    SELECT
        order_id,
        m['start'] start_time,
        m['end'] end_time,
        CASE
            WHEN m['end'] IS NOT NULL THEN '2020-01-02'
            ELSE '9999-12-31'
        END ymd
    FROM
        t1
    ),
    old AS (SELECT * FROM ec.dwd_order WHERE ymd='9999-12-31')
INSERT OVERWRITE TABLE ec.dwd_order PARTITION(ymd)
SELECT
    NVL(new.order_id,old.order_id) order_id,
    NVL(new.start_time,old.start_time) start_time,
    NVL(new.end_time,old.end_time) end_time,
    NVL(new.ymd,old.ymd) ymd
FROM new
FULL OUTER JOIN old
ON new.order_id=old.order_id;

写入后结果

补充

上面的订单状态比较简单,这个全一点,SQL的思路是一样的

下单
支付
主动或被动确认
申请退款
申请退款
主动取消
1小时内没付款
7天内没申请退款
开始
待支付
已支付
确认收货
退款中
退款完成
已取消
支付过期
结束
状态时间字段说明备注
待支付create_time创建时间
已支付pay_time支付时间
确认收货confirm_time确认时间到货后7天内,买家可主动确认收货或退款;7天后没有操作将会自动确认收货
已取消cancel_time取消时间下单后支付前,主动取消订单
支付过期overdue_time过期时间下单后1小时内没有支付
退款中refund_time退款申请时间
退款完成refund_finish_time退款完成时间
结束end_time结束时间
WITH
    t1 AS(
        SELECT
            order_id,
            STR_TO_MAP(CONCAT_WS(',',COLLECT_SET(CONCAT(order_status,'=',operation_time))),',','=') m
        FROM ec.ods_order_status
        WHERE ymd='2020-01-01'
        GROUP BY order_id
    )
SELECT
    order_id,
    m['已支付'] pay_time,
    m['已取消'] cancel_time,
    m['确认收货'] confirm_time,
    m['退款中'] refund_time,
    m['退款完成'] refund_finish_time,
    m['支付过期'] overdue_time,
    m['结束'] end_time,
    CASE
        WHEN m['结束'] IS NOT NULL THEN '昨天'
        ELSE '9999-12-31'
    END ymd
FROM t1;

另外,订单状态表(ods_order_status)要和订单表(ods_order)连接,本文就不JOIN了

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小基基o_O

您的鼓励是我创作的巨大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值