Ver Fonte

feat(dwd/trd): dwd_trd_order_pay_apd_d DDL + init + sche(订单支付事件 + 维度退化 + 金额派生)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tianyu.chu há 3 dias atrás
pai
commit
d840682183

+ 89 - 0
jobs/dwd/trd/dwd_trd_order_pay_apd_d.sql

@@ -0,0 +1,89 @@
+-- 作者:tianyu.chu
+-- 日期:2026-05-10
+-- 工单:(无)
+-- 目的:dwd_trd_order_pay_apd_d 日常增量(kb/27 §1.4 + §2):
+--      扫 ods.dt=${dt} + 过滤业务时间 DATE_FORMAT(payment_success_time)=${dt} + status / order_type 支付成功 +
+--      ROW_NUMBER 取每 order_id 最新版本 +
+--      LEFT JOIN dim_trd_card_group_ful_d.dt=${dt} 维度退化 +
+--      11 字段金额 mer_act% 派生(kb/27 §2.5)+ 写入 dwd dt=${dt} 单分区
+-- 状态:[草案]
+-- 备注:sched=T,${dt}=T-1;
+--      _apd_d 单分区不回算(ODS 漂移已在 ODS 层归位,kb/27 §1.4);
+--      过滤 DATE(payment_success_time)=${dt} 取业务时间是 ${dt} 的事件(排除"今天 update 的旧订单"误归);
+--      前置 DS DEPENDENT:ods_trd_card_group_order_info_inc_d.dt=${dt} + dim_trd_card_group_ful_d.dt=${dt}
+
+INSERT OVERWRITE TABLE dwd.dwd_trd_order_pay_apd_d PARTITION (dt='${dt}')
+SELECT
+    o.id                                                                                AS order_id,
+    o.order_no                                                                          AS order_no,
+    o.combination_no                                                                    AS combination_no,
+    o.give_order_id                                                                     AS give_order_id,
+    o.user_id                                                                           AS user_id,
+    o.merchant_id                                                                       AS merchant_id,
+    o.group_info_id                                                                     AS group_info_id,
+    cg.name                                                                             AS group_name,
+    cg.list_id                                                                          AS list_id,
+    cg.panini_list_id                                                                   AS panini_list_id,
+    cg.category                                                                         AS category,
+    cg.manufacturer                                                                     AS manufacturer,
+    cg.sets                                                                             AS sets,
+    cg.year                                                                             AS year,
+    o.shipping_address_id                                                               AS shipping_address_id,
+    o.purchase_count                                                                    AS purchase_cnt,
+    o.give_num                                                                          AS give_cnt,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.accounts_payable / 100.00, 2)   ELSE o.accounts_payable    END AS payable_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.point / 100.00, 2)              ELSE o.actual_payment      END AS pay_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.trade_amount / 100.00, 2)       ELSE o.trade_amount        END AS trade_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.settlement_amount / 100.00, 2)  ELSE o.settlement_amount   END AS settle_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.card_price / 100.00, 2)         ELSE o.card_price          END AS card_price_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.act_price / 100.00, 2)          ELSE o.act_price           END AS act_price_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.discount / 100.00, 2)           ELSE o.discount            END AS merchant_discount_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.platform_discount / 100.00, 2)  ELSE o.platform_discount   END AS platform_discount_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.member_discount / 100.00, 2)    ELSE o.member_discount     END AS member_discount_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.act_discount / 100.00, 2)       ELSE o.act_discount        END AS act_discount_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.point_deduct / 100.00, 2)       ELSE o.point_deduct        END AS point_deduct_amt_cny,
+    o.shipping_cost                                                                     AS shipping_amt_cny,
+    o.shipping_free_amount                                                              AS shipping_free_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.discount_amount / 100.00, 2)    ELSE o.discount_amount     END AS discount_amount_amt_cny,
+    o.point                                                                             AS point,
+    o.discount_point                                                                    AS discount_point,
+    o.coupon                                                                            AS coupon,
+    o.platform_coupon                                                                   AS platform_coupon,
+    o.shipping_free_id                                                                  AS shipping_free_id,
+    o.payment_type                                                                      AS payment_type,
+    o.payment_sub_type                                                                  AS payment_sub_type,
+    o.payment_status                                                                    AS payment_status,
+    o.payment_status_desc                                                               AS payment_status_desc,
+    o.payment_time                                                                      AS payment_time,
+    o.payment_success_time                                                              AS payment_success_time,
+    o.pay_record                                                                        AS pay_record,
+    o.order_type                                                                        AS order_type,
+    o.order_sub_type                                                                    AS order_sub_type,
+    o.give_user_code                                                                    AS give_user_code,
+    o.anonymous                                                                         AS anonymous,
+    o.pick_up_type                                                                      AS pick_up_type,
+    o.point_type                                                                        AS point_type,
+    o.open_self                                                                         AS open_self,
+    o.create_time                                                                       AS order_create_time,
+    o.expire_time                                                                       AS expire_time,
+    o.is_deleted                                                                        AS is_deleted,
+    CURRENT_TIMESTAMP()                                                                 AS etl_time
+FROM (
+    SELECT *
+    FROM (
+        SELECT *,
+            ROW_NUMBER() OVER (
+                PARTITION BY id
+                ORDER BY COALESCE(update_time, create_time) DESC
+            ) AS rn
+        FROM ods.ods_trd_card_group_order_info_inc_d
+        WHERE dt = '${dt}'
+          AND order_type = 'group'
+          AND status IN (101, 103, 104, 105, 106, 301, 302)
+          AND DATE_FORMAT(payment_success_time, 'yyyyMMdd') = '${dt}'
+    ) t
+    WHERE t.rn = 1
+) o
+LEFT JOIN dim.dim_trd_card_group_ful_d cg
+    ON o.group_info_id = cg.group_info_id
+   AND cg.dt = '${dt}';

+ 93 - 0
manual/backfill/20260510_dwd_trd_order_pay_apd_d_init.sql

@@ -0,0 +1,93 @@
+-- 作者:tianyu.chu
+-- 日期:2026-05-10
+-- 工单:(无)
+-- 目的:dwd_trd_order_pay_apd_d 初始化(kb/27 §2):
+--      扫 ods 全量历史订单 + ROW_NUMBER 取每 order_id 最新版本 +
+--      过滤支付成功(order_type='group' AND status IN (101,103,104,105,106,301,302))+
+--      LEFT JOIN dim_trd_card_group_ful_d.dt=${pdt} 维度退化 +
+--      11 字段金额 mer_act% 派生(kb/27 §2.5)+
+--      DATE_FORMAT(payment_success_time, 'yyyyMMdd') 动态分区写入
+-- 状态:[待执行]
+-- 备注:跑一次后由 jobs/dwd/trd/dwd_trd_order_pay_apd_d.sql 接管日常增量;
+--      历史业务时间跨 2021-10 ~ ${dt},动态分区上限 SET 提到 2000;
+--      维度退化 join 用 dim.dt=${pdt}(init 跑当时 dim 已灌入的首日分区);
+--      ods 跨 dt 不去重 → ROW_NUMBER over order_id ORDER BY update_time DESC 取最新
+
+set hive.exec.max.dynamic.partitions=2000;
+set hive.exec.max.dynamic.partitions.pernode=200;
+
+INSERT OVERWRITE TABLE dwd.dwd_trd_order_pay_apd_d PARTITION (dt)
+SELECT
+    o.id                                                                                AS order_id,
+    o.order_no                                                                          AS order_no,
+    o.combination_no                                                                    AS combination_no,
+    o.give_order_id                                                                     AS give_order_id,
+    o.user_id                                                                           AS user_id,
+    o.merchant_id                                                                       AS merchant_id,
+    o.group_info_id                                                                     AS group_info_id,
+    cg.name                                                                             AS group_name,
+    cg.list_id                                                                          AS list_id,
+    cg.panini_list_id                                                                   AS panini_list_id,
+    cg.category                                                                         AS category,
+    cg.manufacturer                                                                     AS manufacturer,
+    cg.sets                                                                             AS sets,
+    cg.year                                                                             AS year,
+    o.shipping_address_id                                                               AS shipping_address_id,
+    o.purchase_count                                                                    AS purchase_cnt,
+    o.give_num                                                                          AS give_cnt,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.accounts_payable / 100.00, 2)   ELSE o.accounts_payable    END AS payable_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.point / 100.00, 2)              ELSE o.actual_payment      END AS pay_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.trade_amount / 100.00, 2)       ELSE o.trade_amount        END AS trade_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.settlement_amount / 100.00, 2)  ELSE o.settlement_amount   END AS settle_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.card_price / 100.00, 2)         ELSE o.card_price          END AS card_price_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.act_price / 100.00, 2)          ELSE o.act_price           END AS act_price_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.discount / 100.00, 2)           ELSE o.discount            END AS merchant_discount_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.platform_discount / 100.00, 2)  ELSE o.platform_discount   END AS platform_discount_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.member_discount / 100.00, 2)    ELSE o.member_discount     END AS member_discount_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.act_discount / 100.00, 2)       ELSE o.act_discount        END AS act_discount_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.point_deduct / 100.00, 2)       ELSE o.point_deduct        END AS point_deduct_amt_cny,
+    o.shipping_cost                                                                     AS shipping_amt_cny,
+    o.shipping_free_amount                                                              AS shipping_free_amt_cny,
+    CASE WHEN o.point_type LIKE 'mer_act%' THEN ROUND(o.discount_amount / 100.00, 2)    ELSE o.discount_amount     END AS discount_amount_amt_cny,
+    o.point                                                                             AS point,
+    o.discount_point                                                                    AS discount_point,
+    o.coupon                                                                            AS coupon,
+    o.platform_coupon                                                                   AS platform_coupon,
+    o.shipping_free_id                                                                  AS shipping_free_id,
+    o.payment_type                                                                      AS payment_type,
+    o.payment_sub_type                                                                  AS payment_sub_type,
+    o.payment_status                                                                    AS payment_status,
+    o.payment_status_desc                                                               AS payment_status_desc,
+    o.payment_time                                                                      AS payment_time,
+    o.payment_success_time                                                              AS payment_success_time,
+    o.pay_record                                                                        AS pay_record,
+    o.order_type                                                                        AS order_type,
+    o.order_sub_type                                                                    AS order_sub_type,
+    o.give_user_code                                                                    AS give_user_code,
+    o.anonymous                                                                         AS anonymous,
+    o.pick_up_type                                                                      AS pick_up_type,
+    o.point_type                                                                        AS point_type,
+    o.open_self                                                                         AS open_self,
+    o.create_time                                                                       AS order_create_time,
+    o.expire_time                                                                       AS expire_time,
+    o.is_deleted                                                                        AS is_deleted,
+    CURRENT_TIMESTAMP()                                                                 AS etl_time,
+    DATE_FORMAT(o.payment_success_time, 'yyyyMMdd')                                     AS dt
+FROM (
+    SELECT *
+    FROM (
+        SELECT *,
+            ROW_NUMBER() OVER (
+                PARTITION BY id
+                ORDER BY COALESCE(update_time, create_time) DESC
+            ) AS rn
+        FROM ods.ods_trd_card_group_order_info_inc_d
+        WHERE order_type = 'group'
+          AND status IN (101, 103, 104, 105, 106, 301, 302)
+          AND payment_success_time IS NOT NULL
+    ) t
+    WHERE t.rn = 1
+) o
+LEFT JOIN dim.dim_trd_card_group_ful_d cg
+    ON o.group_info_id = cg.group_info_id
+   AND cg.dt = '${pdt}';

+ 74 - 0
manual/ddl/dwd/trd/dwd_trd_order_pay_apd_d_create.sql

@@ -0,0 +1,74 @@
+-- 作者:tianyu.chu
+-- 日期:2026-05-10
+-- 工单:(无)
+-- 目的:订单支付明细事件追加表(kb/27 §2 dwd_trd_order_pay_apd_d)
+-- 状态:[草案]
+-- 备注:dt 锚点 = DATE(payment_success_time) 业务时间分区(kb/27 §2.3);
+--      支付成功判定:order_type='group' AND status IN (101,103,104,105,106,301,302)(kb/27 §2.1);
+--      11 字段金额按 mer_act% 通式派生 + Net Revenue 特例(kb/27 §2.5);
+--      维度退化:category/manufacturer/sets/year/group_name/list_id/panini_list_id 来自 dim_trd_card_group_ful_d;
+--      字段类型对齐 ods(整数全 BIGINT,详见 kb/20 §8.4.1 + ADR-06);
+--      _apd_d 事件不可变,只装支付那一刻的事实快照(状态字段 status/serve_status 等归 dim_trd_order_zip_d 拉链)
+
+DROP TABLE IF EXISTS dwd.dwd_trd_order_pay_apd_d;
+
+CREATE EXTERNAL TABLE IF NOT EXISTS dwd.dwd_trd_order_pay_apd_d (
+    order_id                       BIGINT         COMMENT '订单 id (PK,源 order.id)',
+    order_no                       STRING         COMMENT '订单编码',
+    combination_no                 STRING         COMMENT '拆分订单关联编号',
+    give_order_id                  BIGINT         COMMENT '赠与关联订单 id',
+    user_id                        BIGINT         COMMENT '用户 id',
+    merchant_id                    BIGINT         COMMENT '商家 id',
+    group_info_id                  BIGINT         COMMENT '拼团 id',
+    group_name                     STRING         COMMENT '拼团名称(维度退化,源 dim_trd_card_group_ful_d.name)',
+    list_id                        BIGINT         COMMENT '商家上线 checklist id(维度退化,业务库快照冗余)',
+    panini_list_id                 BIGINT         COMMENT '帕尼尼 list id(维度退化,业务库快照冗余)',
+    category                       STRING         COMMENT '品类(lv2,维度退化,DIM 已清洗,权威源)',
+    manufacturer                   STRING         COMMENT '厂商(维度退化)',
+    sets                           STRING         COMMENT '系列(维度退化)',
+    year                           STRING         COMMENT '年份/赛季(维度退化)',
+    shipping_address_id            BIGINT         COMMENT '收货地址 id',
+    purchase_cnt                   BIGINT         COMMENT '购买份数(源 purchase_count)',
+    give_cnt                       BIGINT         COMMENT '赠送个数(源 give_num)',
+    payable_amt_cny                DECIMAL(20,4)  COMMENT 'GMV(派生 accounts_payable,见 kb/27 §2.5)',
+    pay_amt_cny                    DECIMAL(20,4)  COMMENT 'Net Revenue 购买偏好口径(派生:mer_act% 时 ROUND(point/100,2),其他 actual_payment,见 kb/27 §2.5)',
+    trade_amt_cny                  DECIMAL(20,4)  COMMENT '订单交易金额(派生 trade_amount)',
+    settle_amt_cny                 DECIMAL(20,4)  COMMENT '结算金额(派生 settlement_amount,支付那一刻=实付,_apd_d 不被退款改写)',
+    card_price_cny                 DECIMAL(20,4)  COMMENT '单价应付(派生 card_price)',
+    act_price_cny                  DECIMAL(20,4)  COMMENT '单价实付(派生 act_price)',
+    merchant_discount_amt_cny      DECIMAL(20,4)  COMMENT '商家折扣抵扣(派生 discount,加 merchant_ 前缀突出商家维度)',
+    platform_discount_amt_cny      DECIMAL(20,4)  COMMENT '平台券抵扣(派生 platform_discount)',
+    member_discount_amt_cny        DECIMAL(20,4)  COMMENT '会员折扣(派生 member_discount)',
+    act_discount_amt_cny           DECIMAL(20,4)  COMMENT '活动折扣 首单等(派生 act_discount)',
+    point_deduct_amt_cny           DECIMAL(20,4)  COMMENT '积分抵扣金额(派生 point_deduct)',
+    shipping_amt_cny               DECIMAL(20,4)  COMMENT '运费(源 shipping_cost,直取不派生)',
+    shipping_free_amt_cny          DECIMAL(20,4)  COMMENT '运费券金额(源 shipping_free_amount,直取不派生)',
+    discount_amount_amt_cny        DECIMAL(20,4)  COMMENT '折扣金额(派生 discount_amount,业务库注释未明确,与 merchant_discount 语义区别 + 最终命名待业务答复)',
+    point                          BIGINT         COMMENT '消耗积分',
+    discount_point                 BIGINT         COMMENT '折扣积分',
+    coupon                         BIGINT         COMMENT '优惠券 id',
+    platform_coupon                BIGINT         COMMENT '平台券 id',
+    shipping_free_id               BIGINT         COMMENT '运费券 id',
+    payment_type                   STRING         COMMENT '支付方式-交易类型',
+    payment_sub_type               STRING         COMMENT '支付子分类',
+    payment_status                 STRING         COMMENT '交易状态',
+    payment_status_desc            STRING         COMMENT '交易状态描述',
+    payment_time                   TIMESTAMP      COMMENT '支付时间',
+    payment_success_time           TIMESTAMP      COMMENT '支付完成时间(dt 锚点)',
+    pay_record                     BIGINT         COMMENT '是否重复支付',
+    order_type                     STRING         COMMENT '订单类型',
+    order_sub_type                 STRING         COMMENT '订单子类型(含赠与)',
+    give_user_code                 STRING         COMMENT '赠与人',
+    anonymous                      BOOLEAN        COMMENT '是否匿名',
+    pick_up_type                   STRING         COMMENT '提货方式',
+    point_type                     STRING         COMMENT '使用积分类型',
+    open_self                      BIGINT         COMMENT '是否商家代拆(默认 0,1=商家待拆)',
+    order_create_time              TIMESTAMP      COMMENT '下单时间(源 order.create_time)',
+    expire_time                    TIMESTAMP      COMMENT '过期时间',
+    is_deleted                     BOOLEAN        COMMENT '软删归一',
+    etl_time                       TIMESTAMP      COMMENT 'ETL 处理时间'
+)
+COMMENT '订单支付明细事件追加表'
+PARTITIONED BY (dt STRING)
+STORED AS ORC
+LOCATION '/user/hive/warehouse/dwd.db/dwd_trd_order_pay_apd_d';