1
This commit is contained in:
@@ -1,67 +0,0 @@
|
||||
-- =============================================================================
|
||||
-- 迁移脚本:扩展助教日度业绩明细表 — 新增定档折算惩罚字段
|
||||
-- 日期:2025-02-24
|
||||
-- 说明:在 dws.dws_assistant_daily_detail 中新增 penalty_minutes、penalty_reason、
|
||||
-- is_exempt、per_hour_contribution 四个字段,支撑定档折算惩罚检测与计算。
|
||||
-- 需求:5.1, 5.2
|
||||
-- =============================================================================
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 1. ALTER TABLE:新增定档折算惩罚字段
|
||||
-- ---------------------------------------------------------------------------
|
||||
ALTER TABLE dws.dws_assistant_daily_detail
|
||||
ADD COLUMN IF NOT EXISTS penalty_minutes NUMERIC(10,2) DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS penalty_reason TEXT,
|
||||
ADD COLUMN IF NOT EXISTS is_exempt BOOLEAN DEFAULT FALSE,
|
||||
ADD COLUMN IF NOT EXISTS per_hour_contribution NUMERIC(14,2);
|
||||
|
||||
COMMENT ON COLUMN dws.dws_assistant_daily_detail.penalty_minutes
|
||||
IS '定档折算惩罚分钟数,无惩罚时为 0';
|
||||
COMMENT ON COLUMN dws.dws_assistant_daily_detail.penalty_reason
|
||||
IS '惩罚原因描述,无惩罚时为 NULL';
|
||||
COMMENT ON COLUMN dws.dws_assistant_daily_detail.is_exempt
|
||||
IS '是否豁免惩罚,TRUE 时跳过惩罚计算';
|
||||
COMMENT ON COLUMN dws.dws_assistant_daily_detail.per_hour_contribution
|
||||
IS '单人每小时贡献流水 = 台费每小时实收单价 / 本次基础课助教人数';
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- =============================================================================
|
||||
-- 回滚脚本(如需撤销)
|
||||
-- =============================================================================
|
||||
-- ALTER TABLE dws.dws_assistant_daily_detail
|
||||
-- DROP COLUMN IF EXISTS penalty_minutes,
|
||||
-- DROP COLUMN IF EXISTS penalty_reason,
|
||||
-- DROP COLUMN IF EXISTS is_exempt,
|
||||
-- DROP COLUMN IF EXISTS per_hour_contribution;
|
||||
|
||||
-- =============================================================================
|
||||
-- 验证 SQL
|
||||
-- =============================================================================
|
||||
-- 1. 确认新增字段存在
|
||||
-- SELECT column_name, data_type, column_default
|
||||
-- FROM information_schema.columns
|
||||
-- WHERE table_schema = 'dws'
|
||||
-- AND table_name = 'dws_assistant_daily_detail'
|
||||
-- AND column_name IN ('penalty_minutes', 'penalty_reason', 'is_exempt', 'per_hour_contribution')
|
||||
-- ORDER BY column_name;
|
||||
-- 预期:4 行
|
||||
|
||||
-- 2. 确认字段类型正确
|
||||
-- SELECT column_name, data_type, numeric_precision, numeric_scale
|
||||
-- FROM information_schema.columns
|
||||
-- WHERE table_schema = 'dws'
|
||||
-- AND table_name = 'dws_assistant_daily_detail'
|
||||
-- AND column_name IN ('penalty_minutes', 'per_hour_contribution')
|
||||
-- ORDER BY column_name;
|
||||
-- 预期:penalty_minutes → numeric(10,2),per_hour_contribution → numeric(14,2)
|
||||
|
||||
-- 3. 确认 is_exempt 默认值
|
||||
-- SELECT column_name, column_default
|
||||
-- FROM information_schema.columns
|
||||
-- WHERE table_schema = 'dws'
|
||||
-- AND table_name = 'dws_assistant_daily_detail'
|
||||
-- AND column_name = 'is_exempt';
|
||||
-- 预期:column_default = 'false'
|
||||
@@ -1,89 +0,0 @@
|
||||
-- =============================================================================
|
||||
-- 迁移脚本:扩展会员消费汇总表 — 新增充值窗口和次均消费字段
|
||||
-- 日期:2025-02-24
|
||||
-- 说明:在 dws.dws_member_consumption_summary 中新增 30/60/90 天充值次数、
|
||||
-- 充值金额以及次均消费额度字段,支撑小程序客户看板展示。
|
||||
-- 需求:3.1, 3.2
|
||||
-- =============================================================================
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 1. ALTER TABLE:新增充值窗口 + 次均消费字段
|
||||
-- ---------------------------------------------------------------------------
|
||||
ALTER TABLE dws.dws_member_consumption_summary
|
||||
ADD COLUMN IF NOT EXISTS recharge_count_30d INTEGER DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS recharge_count_60d INTEGER DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS recharge_count_90d INTEGER DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS recharge_amount_30d NUMERIC(14,2) DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS recharge_amount_60d NUMERIC(14,2) DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS recharge_amount_90d NUMERIC(14,2) DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS avg_ticket_amount NUMERIC(14,2) DEFAULT 0;
|
||||
|
||||
COMMENT ON COLUMN dws.dws_member_consumption_summary.recharge_count_30d
|
||||
IS '近 30 天充值次数';
|
||||
COMMENT ON COLUMN dws.dws_member_consumption_summary.recharge_count_60d
|
||||
IS '近 60 天充值次数';
|
||||
COMMENT ON COLUMN dws.dws_member_consumption_summary.recharge_count_90d
|
||||
IS '近 90 天充值次数';
|
||||
COMMENT ON COLUMN dws.dws_member_consumption_summary.recharge_amount_30d
|
||||
IS '近 30 天充值金额';
|
||||
COMMENT ON COLUMN dws.dws_member_consumption_summary.recharge_amount_60d
|
||||
IS '近 60 天充值金额';
|
||||
COMMENT ON COLUMN dws.dws_member_consumption_summary.recharge_amount_90d
|
||||
IS '近 90 天充值金额';
|
||||
COMMENT ON COLUMN dws.dws_member_consumption_summary.avg_ticket_amount
|
||||
IS '次均消费额度 = total_consume_amount / MAX(total_visit_count, 1)';
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- =============================================================================
|
||||
-- 回滚脚本(如需撤销)
|
||||
-- =============================================================================
|
||||
-- ALTER TABLE dws.dws_member_consumption_summary
|
||||
-- DROP COLUMN IF EXISTS recharge_count_30d,
|
||||
-- DROP COLUMN IF EXISTS recharge_count_60d,
|
||||
-- DROP COLUMN IF EXISTS recharge_count_90d,
|
||||
-- DROP COLUMN IF EXISTS recharge_amount_30d,
|
||||
-- DROP COLUMN IF EXISTS recharge_amount_60d,
|
||||
-- DROP COLUMN IF EXISTS recharge_amount_90d,
|
||||
-- DROP COLUMN IF EXISTS avg_ticket_amount;
|
||||
|
||||
-- =============================================================================
|
||||
-- 验证 SQL
|
||||
-- =============================================================================
|
||||
-- 1. 确认新增字段存在
|
||||
-- SELECT column_name, data_type, column_default
|
||||
-- FROM information_schema.columns
|
||||
-- WHERE table_schema = 'dws'
|
||||
-- AND table_name = 'dws_member_consumption_summary'
|
||||
-- AND column_name IN (
|
||||
-- 'recharge_count_30d', 'recharge_count_60d', 'recharge_count_90d',
|
||||
-- 'recharge_amount_30d', 'recharge_amount_60d', 'recharge_amount_90d',
|
||||
-- 'avg_ticket_amount'
|
||||
-- )
|
||||
-- ORDER BY column_name;
|
||||
-- 预期:7 行
|
||||
|
||||
-- 2. 确认字段类型正确
|
||||
-- SELECT column_name, data_type, numeric_precision, numeric_scale
|
||||
-- FROM information_schema.columns
|
||||
-- WHERE table_schema = 'dws'
|
||||
-- AND table_name = 'dws_member_consumption_summary'
|
||||
-- AND column_name LIKE 'recharge_amount%'
|
||||
-- ORDER BY column_name;
|
||||
-- 预期:3 行,data_type = numeric, precision = 14, scale = 2
|
||||
|
||||
-- 3. 确认注释已设置
|
||||
-- SELECT c.column_name,
|
||||
-- pgd.description
|
||||
-- FROM information_schema.columns c
|
||||
-- JOIN pg_catalog.pg_statio_all_tables st
|
||||
-- ON c.table_schema = st.schemaname AND c.table_name = st.relname
|
||||
-- JOIN pg_catalog.pg_description pgd
|
||||
-- ON pgd.objoid = st.relid AND pgd.objsubid = c.ordinal_position
|
||||
-- WHERE c.table_schema = 'dws'
|
||||
-- AND c.table_name = 'dws_member_consumption_summary'
|
||||
-- AND c.column_name LIKE 'recharge%'
|
||||
-- ORDER BY c.column_name;
|
||||
-- 预期:6 行,description 非空
|
||||
@@ -1,89 +0,0 @@
|
||||
-- =============================================================================
|
||||
-- 迁移脚本:创建助教订单流水四项统计表
|
||||
-- 日期:2025-02-24
|
||||
-- 说明:新建 dws.dws_assistant_order_contribution 表,存储每名助教每日的
|
||||
-- 订单总流水、订单净流水、时效贡献流水、时效净贡献四项统计数据。
|
||||
-- 需求:1.1, 1.2, 1.3, 1.4, 1.5
|
||||
-- =============================================================================
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 1. 建表:dws.dws_assistant_order_contribution
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dws.dws_assistant_order_contribution (
|
||||
contribution_id BIGSERIAL PRIMARY KEY,
|
||||
site_id INTEGER NOT NULL,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
assistant_id BIGINT NOT NULL,
|
||||
assistant_nickname VARCHAR(100),
|
||||
stat_date DATE NOT NULL,
|
||||
|
||||
-- 四项统计
|
||||
order_gross_revenue NUMERIC(14,2) DEFAULT 0, -- 订单总流水
|
||||
order_net_revenue NUMERIC(14,2) DEFAULT 0, -- 订单净流水
|
||||
time_weighted_revenue NUMERIC(14,2) DEFAULT 0, -- 时效贡献流水
|
||||
time_weighted_net_revenue NUMERIC(14,2) DEFAULT 0, -- 时效净贡献
|
||||
|
||||
-- 辅助字段
|
||||
order_count INTEGER DEFAULT 0, -- 参与订单数
|
||||
total_service_seconds INTEGER DEFAULT 0, -- 总服务时长(秒)
|
||||
|
||||
-- 元数据
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE dws.dws_assistant_order_contribution
|
||||
IS '助教订单流水四项统计表,粒度 (site_id, assistant_id, stat_date)';
|
||||
|
||||
COMMENT ON COLUMN dws.dws_assistant_order_contribution.order_gross_revenue
|
||||
IS '订单总流水 = 台费 + 酒水食品 + 所有助教服务费';
|
||||
COMMENT ON COLUMN dws.dws_assistant_order_contribution.order_net_revenue
|
||||
IS '订单净流水 = 订单总流水 - 所有助教服务分成';
|
||||
COMMENT ON COLUMN dws.dws_assistant_order_contribution.time_weighted_revenue
|
||||
IS '时效贡献流水 = 台费按时长分摊 + 个人服务费 + 酒水食品按时长比例';
|
||||
COMMENT ON COLUMN dws.dws_assistant_order_contribution.time_weighted_net_revenue
|
||||
IS '时效净贡献 = 时效贡献流水 - 个人服务分成';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 2. 唯一索引:确保 (site_id, assistant_id, stat_date) 唯一
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_aoc_site_assistant_date
|
||||
ON dws.dws_assistant_order_contribution (site_id, assistant_id, stat_date);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 3. 查询索引:按门店+日期查询
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE INDEX IF NOT EXISTS idx_aoc_stat_date
|
||||
ON dws.dws_assistant_order_contribution (site_id, stat_date);
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- =============================================================================
|
||||
-- 回滚脚本(如需撤销)
|
||||
-- =============================================================================
|
||||
-- DROP INDEX IF EXISTS dws.idx_aoc_stat_date;
|
||||
-- DROP INDEX IF EXISTS dws.idx_aoc_site_assistant_date;
|
||||
-- DROP TABLE IF EXISTS dws.dws_assistant_order_contribution;
|
||||
|
||||
-- =============================================================================
|
||||
-- 验证 SQL
|
||||
-- =============================================================================
|
||||
-- 1. 确认表存在
|
||||
-- SELECT table_schema, table_name FROM information_schema.tables
|
||||
-- WHERE table_schema = 'dws' AND table_name = 'dws_assistant_order_contribution';
|
||||
-- 预期:1 行
|
||||
|
||||
-- 2. 确认字段完整
|
||||
-- SELECT column_name, data_type, column_default
|
||||
-- FROM information_schema.columns
|
||||
-- WHERE table_schema = 'dws' AND table_name = 'dws_assistant_order_contribution'
|
||||
-- ORDER BY ordinal_position;
|
||||
-- 预期:16 行
|
||||
|
||||
-- 3. 确认索引存在
|
||||
-- SELECT indexname FROM pg_indexes
|
||||
-- WHERE schemaname = 'dws' AND tablename = 'dws_assistant_order_contribution'
|
||||
-- ORDER BY indexname;
|
||||
-- 预期:3 行(PK + idx_aoc_site_assistant_date + idx_aoc_stat_date)
|
||||
@@ -1,34 +0,0 @@
|
||||
-- =============================================================================
|
||||
-- RLS 视图:助教订单流水统计 + 已有视图重建(包含新增字段)
|
||||
-- 目标库:test_etl_feiqiu(测试)/ etl_feiqiu(生产)
|
||||
-- 前提:dws.dws_assistant_order_contribution 表已创建;
|
||||
-- dws.dws_member_consumption_summary 已新增充值窗口字段;
|
||||
-- dws.dws_assistant_daily_detail 已新增惩罚字段
|
||||
-- =============================================================================
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 1. 新建:助教订单流水统计 RLS 视图
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE OR REPLACE VIEW app.v_dws_assistant_order_contribution AS
|
||||
SELECT * FROM dws.dws_assistant_order_contribution
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
GRANT SELECT ON app.v_dws_assistant_order_contribution TO app_reader;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 2. 重建已有视图(使用 SELECT * 以包含新增字段)
|
||||
-- 原视图使用显式字段列表,新增字段不会自动暴露
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE OR REPLACE VIEW app.v_dws_member_consumption_summary AS
|
||||
SELECT * FROM dws.dws_member_consumption_summary
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_assistant_daily_detail AS
|
||||
SELECT * FROM dws.dws_assistant_daily_detail
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
-- =============================================================================
|
||||
-- 回滚脚本
|
||||
-- =============================================================================
|
||||
-- DROP VIEW IF EXISTS app.v_dws_assistant_order_contribution;
|
||||
-- 对于已有视图的回滚,需要用旧的显式字段列表重建(参见 2026-02-24__p1_create_app_schema_rls_views.sql)
|
||||
@@ -1,139 +0,0 @@
|
||||
-- =============================================================================
|
||||
-- 迁移脚本:创建员工档案 ODS + DWD 表
|
||||
-- 日期:2026-02-22
|
||||
-- 说明:从 SearchSystemStaffInfo API 抓取员工数据,ODS 落地后清洗至 DWD 维度表
|
||||
-- 需求:US-1, US-2, US-3
|
||||
-- =============================================================================
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 1. ODS 层:ods.staff_info_master
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE ods.staff_info_master (
|
||||
id BIGINT NOT NULL,
|
||||
tenant_id BIGINT,
|
||||
site_id BIGINT,
|
||||
tenant_org_id BIGINT,
|
||||
system_user_id BIGINT,
|
||||
staff_name TEXT,
|
||||
alias_name TEXT,
|
||||
mobile TEXT,
|
||||
avatar TEXT,
|
||||
gender INTEGER,
|
||||
job TEXT,
|
||||
job_num TEXT,
|
||||
staff_identity INTEGER,
|
||||
status INTEGER,
|
||||
account_status INTEGER,
|
||||
system_role_id INTEGER,
|
||||
rank_id INTEGER,
|
||||
rank_name TEXT,
|
||||
new_rank_id INTEGER,
|
||||
new_staff_identity INTEGER,
|
||||
leave_status INTEGER,
|
||||
entry_time TIMESTAMP WITHOUT TIME ZONE,
|
||||
resign_time TIMESTAMP WITHOUT TIME ZONE,
|
||||
create_time TIMESTAMP WITHOUT TIME ZONE,
|
||||
is_delete INTEGER,
|
||||
is_reserve INTEGER,
|
||||
shop_name TEXT,
|
||||
site_label TEXT,
|
||||
cashier_point_id BIGINT,
|
||||
cashier_point_name TEXT,
|
||||
group_id BIGINT,
|
||||
group_name TEXT,
|
||||
staff_profile_id BIGINT,
|
||||
auth_code TEXT,
|
||||
auth_code_create TIMESTAMP WITHOUT TIME ZONE,
|
||||
ding_talk_synced INTEGER,
|
||||
salary_grant_enabled INTEGER,
|
||||
entry_type INTEGER,
|
||||
entry_sign_status INTEGER,
|
||||
resign_sign_status INTEGER,
|
||||
criticism_status INTEGER,
|
||||
user_roles JSONB,
|
||||
-- ETL 元数据
|
||||
content_hash TEXT NOT NULL,
|
||||
source_file TEXT,
|
||||
fetched_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
|
||||
payload JSONB NOT NULL
|
||||
);
|
||||
|
||||
COMMENT ON TABLE ods.staff_info_master IS '员工档案主数据(来源:SearchSystemStaffInfo API)';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 2. DWD 层:dwd.dim_staff(主表,核心业务字段,SCD2)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE dwd.dim_staff (
|
||||
staff_id BIGINT NOT NULL,
|
||||
staff_name TEXT,
|
||||
alias_name TEXT,
|
||||
mobile TEXT,
|
||||
gender INTEGER,
|
||||
job TEXT,
|
||||
tenant_id BIGINT,
|
||||
site_id BIGINT,
|
||||
system_role_id INTEGER,
|
||||
staff_identity INTEGER,
|
||||
status INTEGER,
|
||||
leave_status INTEGER,
|
||||
entry_time TIMESTAMP WITH TIME ZONE,
|
||||
resign_time TIMESTAMP WITH TIME ZONE,
|
||||
is_delete INTEGER,
|
||||
-- SCD2
|
||||
scd2_start_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
scd2_end_time TIMESTAMP WITH TIME ZONE,
|
||||
scd2_is_current INTEGER,
|
||||
scd2_version INTEGER,
|
||||
PRIMARY KEY (staff_id, scd2_start_time)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE dwd.dim_staff IS '员工档案维度主表(SCD2)';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 3. DWD 层:dwd.dim_staff_ex(扩展表,次要/低频变更字段,SCD2)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE dwd.dim_staff_ex (
|
||||
staff_id BIGINT NOT NULL,
|
||||
avatar TEXT,
|
||||
job_num TEXT,
|
||||
account_status INTEGER,
|
||||
rank_id INTEGER,
|
||||
rank_name TEXT,
|
||||
new_rank_id INTEGER,
|
||||
new_staff_identity INTEGER,
|
||||
is_reserve INTEGER,
|
||||
shop_name TEXT,
|
||||
site_label TEXT,
|
||||
tenant_org_id BIGINT,
|
||||
system_user_id BIGINT,
|
||||
cashier_point_id BIGINT,
|
||||
cashier_point_name TEXT,
|
||||
group_id BIGINT,
|
||||
group_name TEXT,
|
||||
staff_profile_id BIGINT,
|
||||
auth_code TEXT,
|
||||
auth_code_create TIMESTAMP WITH TIME ZONE,
|
||||
ding_talk_synced INTEGER,
|
||||
salary_grant_enabled INTEGER,
|
||||
entry_type INTEGER,
|
||||
entry_sign_status INTEGER,
|
||||
resign_sign_status INTEGER,
|
||||
criticism_status INTEGER,
|
||||
create_time TIMESTAMP WITH TIME ZONE,
|
||||
user_roles JSONB,
|
||||
-- SCD2
|
||||
scd2_start_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
scd2_end_time TIMESTAMP WITH TIME ZONE,
|
||||
scd2_is_current INTEGER,
|
||||
scd2_version INTEGER,
|
||||
PRIMARY KEY (staff_id, scd2_start_time)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE dwd.dim_staff_ex IS '员工档案维度扩展表(SCD2)';
|
||||
|
||||
-- =============================================================================
|
||||
-- 回滚脚本(如需撤销)
|
||||
-- DROP TABLE IF EXISTS dwd.dim_staff_ex;
|
||||
-- DROP TABLE IF EXISTS dwd.dim_staff;
|
||||
-- DROP TABLE IF EXISTS ods.staff_info_master;
|
||||
-- =============================================================================
|
||||
@@ -1,70 +0,0 @@
|
||||
-- =============================================================================
|
||||
-- 迁移脚本:创建 dws.dws_member_spending_power_index 表
|
||||
-- 日期:2026-02-23
|
||||
-- 说明:SPI(消费力指数)结果表,存储会员级消费力评分及中间特征
|
||||
-- 需求:1.1, 1.2, 1.3, 1.4, 1.5
|
||||
-- =============================================================================
|
||||
|
||||
-- 序列(BIGSERIAL 自动创建,此处显式声明以保持与项目风格一致)
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_member_spending_power_index_spi_id_seq AS bigint;
|
||||
|
||||
-- 主表
|
||||
CREATE TABLE dws.dws_member_spending_power_index (
|
||||
spi_id BIGINT DEFAULT nextval('dws.dws_member_spending_power_index_spi_id_seq'::regclass) NOT NULL,
|
||||
site_id INTEGER NOT NULL,
|
||||
member_id BIGINT NOT NULL,
|
||||
|
||||
-- 基础特征
|
||||
spend_30 NUMERIC(14,2) DEFAULT 0, -- 近30天消费总额
|
||||
spend_90 NUMERIC(14,2) DEFAULT 0, -- 近90天消费总额
|
||||
recharge_90 NUMERIC(14,2) DEFAULT 0, -- 近90天充值总额
|
||||
orders_30 INTEGER DEFAULT 0, -- 近30天消费笔数
|
||||
orders_90 INTEGER DEFAULT 0, -- 近90天消费笔数
|
||||
visit_days_30 INTEGER DEFAULT 0, -- 近30天消费日数(按天去重)
|
||||
visit_days_90 INTEGER DEFAULT 0, -- 近90天消费日数(按天去重)
|
||||
avg_ticket_90 NUMERIC(14,2) DEFAULT 0, -- 90天客单价
|
||||
active_weeks_90 INTEGER DEFAULT 0, -- 近90天有消费的自然周数(最多13)
|
||||
daily_spend_ewma_90 NUMERIC(14,2) DEFAULT 0, -- 日消费 EWMA
|
||||
|
||||
-- 子分(Raw:算法直接计算的未归一化分数)
|
||||
score_level_raw NUMERIC(10,4) DEFAULT 0, -- Level 子分原始分
|
||||
score_speed_raw NUMERIC(10,4) DEFAULT 0, -- Speed 子分原始分
|
||||
score_stability_raw NUMERIC(10,4) DEFAULT 0, -- Stability 子分原始分
|
||||
|
||||
-- 子分(Display:归一化到 0-10 的展示分)
|
||||
score_level_display NUMERIC(5,2) DEFAULT 0,
|
||||
score_speed_display NUMERIC(5,2) DEFAULT 0,
|
||||
score_stability_display NUMERIC(5,2) DEFAULT 0,
|
||||
|
||||
-- 总分
|
||||
raw_score NUMERIC(10,4) DEFAULT 0, -- SPI 原始分(加权合成)
|
||||
display_score NUMERIC(5,2) DEFAULT 0, -- SPI 展示分(0-10)
|
||||
|
||||
-- 元数据
|
||||
calc_time TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
|
||||
-- 主键
|
||||
CONSTRAINT dws_member_spending_power_index_pkey PRIMARY KEY (spi_id)
|
||||
);
|
||||
|
||||
-- 唯一约束(业务主键:一个门店一个会员只有一条记录)
|
||||
CREATE UNIQUE INDEX idx_spi_site_member
|
||||
ON dws.dws_member_spending_power_index (site_id, member_id);
|
||||
|
||||
-- 查询索引(按门店查询展示分排名)
|
||||
CREATE INDEX idx_spi_display_score
|
||||
ON dws.dws_member_spending_power_index (site_id, display_score DESC);
|
||||
|
||||
-- 序列归属
|
||||
ALTER SEQUENCE dws.dws_member_spending_power_index_spi_id_seq
|
||||
OWNED BY dws.dws_member_spending_power_index.spi_id;
|
||||
|
||||
-- =============================================================================
|
||||
-- 回滚脚本(如需撤销)
|
||||
-- DROP INDEX IF EXISTS dws.idx_spi_display_score;
|
||||
-- DROP INDEX IF EXISTS dws.idx_spi_site_member;
|
||||
-- DROP TABLE IF EXISTS dws.dws_member_spending_power_index;
|
||||
-- DROP SEQUENCE IF EXISTS dws.dws_member_spending_power_index_spi_id_seq;
|
||||
-- =============================================================================
|
||||
@@ -1,78 +0,0 @@
|
||||
-- 迁移:新增 goodsStockWarningInfo 嵌套字段到 ODS 和 DWD
|
||||
-- 日期:2026-02-24
|
||||
-- 关联:一致性检查报告发现 API 独有字段 goodsStockWarningInfo 未映射
|
||||
-- 字段来源:API store_goods_master -> goodsStockWarningInfo 嵌套对象
|
||||
-- - sales_day: 销售天数(用于库存预警计算)
|
||||
-- - warning_day_max: 预警天数上限
|
||||
-- - warning_day_min: 预警天数下限
|
||||
-- - site_goods_id / tenant_goods_id: 已有冗余字段,不重复收录
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- =============================================================================
|
||||
-- 1. ODS 层:ods.store_goods_master 新增 3 列
|
||||
-- =============================================================================
|
||||
ALTER TABLE ods.store_goods_master
|
||||
ADD COLUMN IF NOT EXISTS warning_sales_day NUMERIC(18,2),
|
||||
ADD COLUMN IF NOT EXISTS warning_day_max INTEGER,
|
||||
ADD COLUMN IF NOT EXISTS warning_day_min INTEGER;
|
||||
|
||||
COMMENT ON COLUMN ods.store_goods_master.warning_sales_day IS
|
||||
'【说明】库存预警参考的日均销量。 【ODS来源】store_goods_master - goodsStockWarningInfo.sales_day。 【JSON字段】store_goods_master.json - data.orderGoodsList - goodsStockWarningInfo.sales_day。';
|
||||
COMMENT ON COLUMN ods.store_goods_master.warning_day_max IS
|
||||
'【说明】库存预警天数上限。 【ODS来源】store_goods_master - goodsStockWarningInfo.warning_day_max。 【JSON字段】store_goods_master.json - data.orderGoodsList - goodsStockWarningInfo.warning_day_max。';
|
||||
COMMENT ON COLUMN ods.store_goods_master.warning_day_min IS
|
||||
'【说明】库存预警天数下限。 【ODS来源】store_goods_master - goodsStockWarningInfo.warning_day_min。 【JSON字段】store_goods_master.json - data.orderGoodsList - goodsStockWarningInfo.warning_day_min。';
|
||||
|
||||
-- =============================================================================
|
||||
-- 2. DWD 层:dwd.dim_store_goods_ex 新增 3 列
|
||||
-- =============================================================================
|
||||
ALTER TABLE dwd.dim_store_goods_ex
|
||||
ADD COLUMN IF NOT EXISTS warning_sales_day NUMERIC(18,2),
|
||||
ADD COLUMN IF NOT EXISTS warning_day_max INTEGER,
|
||||
ADD COLUMN IF NOT EXISTS warning_day_min INTEGER;
|
||||
|
||||
COMMENT ON COLUMN dwd.dim_store_goods_ex.warning_sales_day IS
|
||||
'【说明】库存预警参考的日均销量。 【ODS来源】store_goods_master - goodsStockWarningInfo.sales_day。 【JSON字段】store_goods_master.json - data.orderGoodsList - goodsStockWarningInfo.sales_day。';
|
||||
COMMENT ON COLUMN dwd.dim_store_goods_ex.warning_day_max IS
|
||||
'【说明】库存预警天数上限。 【ODS来源】store_goods_master - goodsStockWarningInfo.warning_day_max。 【JSON字段】store_goods_master.json - data.orderGoodsList - goodsStockWarningInfo.warning_day_max。';
|
||||
COMMENT ON COLUMN dwd.dim_store_goods_ex.warning_day_min IS
|
||||
'【说明】库存预警天数下限。 【ODS来源】store_goods_master - goodsStockWarningInfo.warning_day_min。 【JSON字段】store_goods_master.json - data.orderGoodsList - goodsStockWarningInfo.warning_day_min。';
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- =============================================================================
|
||||
-- 回滚策略
|
||||
-- =============================================================================
|
||||
-- ALTER TABLE ods.store_goods_master
|
||||
-- DROP COLUMN IF EXISTS warning_sales_day,
|
||||
-- DROP COLUMN IF EXISTS warning_day_max,
|
||||
-- DROP COLUMN IF EXISTS warning_day_min;
|
||||
-- ALTER TABLE dwd.dim_store_goods_ex
|
||||
-- DROP COLUMN IF EXISTS warning_sales_day,
|
||||
-- DROP COLUMN IF EXISTS warning_day_max,
|
||||
-- DROP COLUMN IF EXISTS warning_day_min;
|
||||
|
||||
-- =============================================================================
|
||||
-- 验证 SQL
|
||||
-- =============================================================================
|
||||
-- 1. 确认 ODS 新列存在
|
||||
-- SELECT column_name, data_type FROM information_schema.columns
|
||||
-- WHERE table_schema = 'ods' AND table_name = 'store_goods_master'
|
||||
-- AND column_name IN ('warning_sales_day', 'warning_day_max', 'warning_day_min')
|
||||
-- ORDER BY column_name;
|
||||
-- 预期:3 行
|
||||
|
||||
-- 2. 确认 DWD 新列存在
|
||||
-- SELECT column_name, data_type FROM information_schema.columns
|
||||
-- WHERE table_schema = 'dwd' AND table_name = 'dim_store_goods_ex'
|
||||
-- AND column_name IN ('warning_sales_day', 'warning_day_max', 'warning_day_min')
|
||||
-- ORDER BY column_name;
|
||||
-- 预期:3 行
|
||||
|
||||
-- 3. 确认注释已设置
|
||||
-- SELECT col_description(
|
||||
-- (SELECT oid FROM pg_class WHERE relname = 'store_goods_master' AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'ods')),
|
||||
-- (SELECT ordinal_position FROM information_schema.columns WHERE table_schema = 'ods' AND table_name = 'store_goods_master' AND column_name = 'warning_sales_day')
|
||||
-- );
|
||||
-- 预期:非空
|
||||
@@ -1,21 +0,0 @@
|
||||
-- 迁移:清理 ODS_ASSISTANT_ABOLISH 残留元数据
|
||||
-- 日期:2026-02-24
|
||||
-- 关联:联调报告发现 meta.etl_task 中仍有 ODS_ASSISTANT_ABOLISH 注册,
|
||||
-- 导致调度器尝试执行已删除的任务并报 ValueError
|
||||
-- 幂等:DELETE WHERE 不存在时无影响
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 1. 清理 meta.etl_task 中的 ODS_ASSISTANT_ABOLISH 注册
|
||||
DELETE FROM meta.etl_task WHERE task_code = 'ODS_ASSISTANT_ABOLISH';
|
||||
|
||||
-- 2. 清理 meta.etl_task 中的旧式 ASSISTANT_ABOLISH 注册(seed_scheduler_tasks.sql 残留)
|
||||
DELETE FROM meta.etl_task WHERE task_code = 'ASSISTANT_ABOLISH';
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- =============================================================================
|
||||
-- 验证 SQL
|
||||
-- =============================================================================
|
||||
-- SELECT * FROM meta.etl_task WHERE task_code IN ('ODS_ASSISTANT_ABOLISH', 'ASSISTANT_ABOLISH');
|
||||
-- 预期:0 行
|
||||
@@ -1,196 +0,0 @@
|
||||
-- =============================================================================
|
||||
-- 迁移脚本:创建 app Schema、RLS 视图层与 app_reader 角色
|
||||
-- 日期:2026-02-24
|
||||
-- 目标库:test_etl_feiqiu(通过 PG_DSN 连接)
|
||||
-- 说明:为 DWD/DWS 层共 35 张表创建带 site_id 行级过滤的 RLS 视图,
|
||||
-- 供业务库通过 postgres_fdw 只读访问。
|
||||
-- cfg_* 配置表无 site_id 列,视图直接 SELECT * 不加过滤。
|
||||
-- dim_member / dim_member_card_account 使用 register_site_id 列过滤。
|
||||
-- dim_staff_ex 无 site_id 列,视图直接 SELECT * 不加过滤。
|
||||
-- 需求:2.1, 2.2, 2.3, 2.4, 2.7, 2.8, 4.1, 4.3, 4.4, 4.5, 4.6
|
||||
-- =============================================================================
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 1. 创建 app Schema
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE SCHEMA IF NOT EXISTS app;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 2. 创建 app_reader 只读角色(条件创建)
|
||||
-- ---------------------------------------------------------------------------
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'app_reader') THEN
|
||||
CREATE ROLE app_reader LOGIN;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 3. DWD 层 RLS 视图(11 张,全部含 site_id 过滤)
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- dim_member 使用 register_site_id 而非 site_id
|
||||
CREATE OR REPLACE VIEW app.v_dim_member AS
|
||||
SELECT * FROM dwd.dim_member
|
||||
WHERE register_site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dim_assistant AS
|
||||
SELECT * FROM dwd.dim_assistant
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
-- dim_member_card_account 使用 register_site_id 而非 site_id
|
||||
CREATE OR REPLACE VIEW app.v_dim_member_card_account AS
|
||||
SELECT * FROM dwd.dim_member_card_account
|
||||
WHERE register_site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dim_table AS
|
||||
SELECT * FROM dwd.dim_table
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dwd_settlement_head AS
|
||||
SELECT * FROM dwd.dwd_settlement_head
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dwd_table_fee_log AS
|
||||
SELECT * FROM dwd.dwd_table_fee_log
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dwd_assistant_service_log AS
|
||||
SELECT * FROM dwd.dwd_assistant_service_log
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dwd_recharge_order AS
|
||||
SELECT * FROM dwd.dwd_recharge_order
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dwd_store_goods_sale AS
|
||||
SELECT * FROM dwd.dwd_store_goods_sale
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dim_staff AS
|
||||
SELECT * FROM dwd.dim_staff
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
-- dim_staff_ex 无 site_id 列,直接 SELECT * 不加过滤
|
||||
CREATE OR REPLACE VIEW app.v_dim_staff_ex AS
|
||||
SELECT * FROM dwd.dim_staff_ex;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 4. DWS 层 RLS 视图 — 含 site_id 过滤(20 张)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE OR REPLACE VIEW app.v_dws_member_consumption_summary AS
|
||||
SELECT * FROM dws.dws_member_consumption_summary
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_member_visit_detail AS
|
||||
SELECT * FROM dws.dws_member_visit_detail
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_member_winback_index AS
|
||||
SELECT * FROM dws.dws_member_winback_index
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_member_newconv_index AS
|
||||
SELECT * FROM dws.dws_member_newconv_index
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_member_recall_index AS
|
||||
SELECT * FROM dws.dws_member_recall_index
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_member_assistant_relation_index AS
|
||||
SELECT * FROM dws.dws_member_assistant_relation_index
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_member_assistant_intimacy AS
|
||||
SELECT * FROM dws.dws_member_assistant_intimacy
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_assistant_daily_detail AS
|
||||
SELECT * FROM dws.dws_assistant_daily_detail
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_assistant_monthly_summary AS
|
||||
SELECT * FROM dws.dws_assistant_monthly_summary
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_assistant_salary_calc AS
|
||||
SELECT * FROM dws.dws_assistant_salary_calc
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_assistant_customer_stats AS
|
||||
SELECT * FROM dws.dws_assistant_customer_stats
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_assistant_finance_analysis AS
|
||||
SELECT * FROM dws.dws_assistant_finance_analysis
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_finance_daily_summary AS
|
||||
SELECT * FROM dws.dws_finance_daily_summary
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_finance_income_structure AS
|
||||
SELECT * FROM dws.dws_finance_income_structure
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_finance_recharge_summary AS
|
||||
SELECT * FROM dws.dws_finance_recharge_summary
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_finance_discount_detail AS
|
||||
SELECT * FROM dws.dws_finance_discount_detail
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_finance_expense_summary AS
|
||||
SELECT * FROM dws.dws_finance_expense_summary
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_platform_settlement AS
|
||||
SELECT * FROM dws.dws_platform_settlement
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_assistant_recharge_commission AS
|
||||
SELECT * FROM dws.dws_assistant_recharge_commission
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_dws_order_summary AS
|
||||
SELECT * FROM dws.dws_order_summary
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 5. DWS 层 cfg_* 配置表视图(4 张,无 site_id,直接 SELECT *)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE OR REPLACE VIEW app.v_cfg_performance_tier AS
|
||||
SELECT * FROM dws.cfg_performance_tier;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_cfg_assistant_level_price AS
|
||||
SELECT * FROM dws.cfg_assistant_level_price;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_cfg_bonus_rules AS
|
||||
SELECT * FROM dws.cfg_bonus_rules;
|
||||
|
||||
CREATE OR REPLACE VIEW app.v_cfg_index_parameters AS
|
||||
SELECT * FROM dws.cfg_index_parameters;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 6. P2 预留(待 P2 完成后取消注释并创建视图)
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- TODO [P2] dws.dws_member_spending_power_index → app.v_dws_member_spending_power_index
|
||||
-- TODO [P2] dws.dws_assistant_order_contribution → app.v_dws_assistant_order_contribution
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 7. 授权:app_reader 对 app Schema 的只读访问
|
||||
-- ---------------------------------------------------------------------------
|
||||
GRANT USAGE ON SCHEMA app TO app_reader;
|
||||
GRANT SELECT ON ALL TABLES IN SCHEMA app TO app_reader;
|
||||
|
||||
-- 未来新建视图自动授权
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT SELECT ON TABLES TO app_reader;
|
||||
|
||||
-- =============================================================================
|
||||
-- 回滚脚本(按逆序执行)
|
||||
-- =============================================================================
|
||||
-- ALTER DEFAULT PRIVILEGES IN SCHEMA app REVOKE SELECT ON TABLES FROM app_reader;
|
||||
-- REVOKE SELECT ON ALL TABLES IN SCHEMA app FROM app_reader;
|
||||
-- REVOKE USAGE ON SCHEMA app FROM app_reader;
|
||||
-- DROP SCHEMA IF EXISTS app CASCADE;
|
||||
-- DROP ROLE IF EXISTS app_reader;
|
||||
@@ -1,34 +0,0 @@
|
||||
-- 新增 dws.biz_date() 函数:将 timestamptz 按营业日分割点归属到对应日期
|
||||
-- 原因:全系统统计时间口径从自然日切换为营业日(默认 08:00 分割),
|
||||
-- 数据库层需要与 Python 侧 business_date() 等价的 SQL 函数,
|
||||
-- 供物化视图和直接查询使用。
|
||||
-- 影响:物化视图 mv_dws_finance_daily_summary_l1..l4、
|
||||
-- mv_dws_assistant_daily_detail_l1..l4 的时间过滤条件将依赖此函数
|
||||
-- 关联需求:Requirements 9.2, 9.4
|
||||
|
||||
CREATE OR REPLACE FUNCTION dws.biz_date(
|
||||
ts timestamptz,
|
||||
cutoff_hour int DEFAULT 8
|
||||
)
|
||||
RETURNS date
|
||||
LANGUAGE sql
|
||||
IMMUTABLE
|
||||
PARALLEL SAFE
|
||||
AS $$
|
||||
SELECT (ts - make_interval(hours => cutoff_hour))::date;
|
||||
$$;
|
||||
|
||||
COMMENT ON FUNCTION dws.biz_date(timestamptz, int) IS
|
||||
'营业日归属函数:将时间戳减去 cutoff_hour 小时后取日期。'
|
||||
'默认 cutoff_hour=8,即 08:00 前的时间戳归属前一天。'
|
||||
'等价于 Python 侧 neozqyy_shared.datetime_utils.business_date()。';
|
||||
|
||||
-- 验证 SQL:
|
||||
-- SELECT dws.biz_date('2026-01-15 07:59:59+08'::timestamptz); -- 预期:2026-01-14
|
||||
-- SELECT dws.biz_date('2026-01-15 08:00:00+08'::timestamptz); -- 预期:2026-01-15
|
||||
-- SELECT dws.biz_date('2026-01-15 23:59:59+08'::timestamptz); -- 预期:2026-01-15
|
||||
-- SELECT dws.biz_date('2026-02-01 07:00:00+08'::timestamptz, 8); -- 预期:2026-01-31(月末边界)
|
||||
-- SELECT dws.biz_date(NOW()); -- 预期:当前营业日
|
||||
|
||||
-- 回滚:
|
||||
-- DROP FUNCTION IF EXISTS dws.biz_date(timestamptz, int);
|
||||
@@ -1,22 +0,0 @@
|
||||
-- 迁移:dws_assistant_order_contribution.site_id integer → bigint
|
||||
-- 原因:site_id 为飞球雪花 ID,值域超出 int32 上限
|
||||
-- 依赖:app.v_dws_assistant_order_contribution 视图需先 DROP 再重建
|
||||
-- 日期:2026-02-27
|
||||
-- 已通过 scripts/ops/_fix_all_int_site_ids.py 执行
|
||||
|
||||
-- 1. DROP 依赖视图
|
||||
DROP VIEW IF EXISTS app.v_dws_assistant_order_contribution CASCADE;
|
||||
|
||||
-- 2. ALTER 列类型
|
||||
ALTER TABLE dws.dws_assistant_order_contribution
|
||||
ALTER COLUMN site_id TYPE bigint;
|
||||
|
||||
-- 3. 重建视图(定义需与原视图一致)
|
||||
-- CREATE OR REPLACE VIEW app.v_dws_assistant_order_contribution AS
|
||||
-- SELECT * FROM dws.dws_assistant_order_contribution;
|
||||
-- 注意:实际视图定义已由脚本自动获取并重建
|
||||
|
||||
-- 回滚(如需):
|
||||
-- DROP VIEW IF EXISTS app.v_dws_assistant_order_contribution CASCADE;
|
||||
-- ALTER TABLE dws.dws_assistant_order_contribution ALTER COLUMN site_id TYPE integer;
|
||||
-- 然后重建视图
|
||||
@@ -1,14 +0,0 @@
|
||||
-- 修复 dws_member_spending_power_index.site_id: integer → bigint
|
||||
-- 原因:site_id 值(如 2790685415443269)超出 int32 范围(max 2147483647),
|
||||
-- 导致 INSERT 时 NumericValueOutOfRange 错误
|
||||
-- 影响:DWS_SPENDING_POWER_INDEX 任务
|
||||
-- 已在 test_etl_feiqiu 执行:2026-02-27
|
||||
|
||||
ALTER TABLE dws.dws_member_spending_power_index
|
||||
ALTER COLUMN site_id TYPE bigint;
|
||||
|
||||
-- 回滚(仅在确认无大值数据时):
|
||||
-- ALTER TABLE dws.dws_member_spending_power_index ALTER COLUMN site_id TYPE integer;
|
||||
|
||||
-- 待处理:dws.dws_assistant_order_contribution.site_id 也是 integer,
|
||||
-- 但有视图 app.v_dws_assistant_order_contribution 依赖,需先 DROP VIEW 再改再重建。
|
||||
@@ -1,138 +0,0 @@
|
||||
-- 重建物化视图:时间过滤条件从自然日切换为营业日
|
||||
-- 原因:全系统统计口径从自然日切换为营业日(默认 08:00 分割),
|
||||
-- 物化视图的 WHERE 条件中 CURRENT_DATE 需替换为 dws.biz_date(NOW()),
|
||||
-- 使视图数据范围与 DWS 任务的营业日口径一致。
|
||||
-- 前置依赖:dws.biz_date() 函数(2026-02-27__add_biz_date_function.sql)
|
||||
-- 影响:8 个物化视图将按营业日口径过滤数据,刷新后生效
|
||||
-- 关联需求:Requirements 9.1, 9.3
|
||||
--
|
||||
-- 变更说明:
|
||||
-- CURRENT_DATE → dws.biz_date(NOW())
|
||||
-- date_trunc('month', CURRENT_DATE::timestamptz) → date_trunc('month', dws.biz_date(NOW())::timestamptz)
|
||||
--
|
||||
-- 注意:物化视图不支持 CREATE OR REPLACE,必须 DROP + CREATE 重建。
|
||||
-- 重建后数据为空(WITH DATA 会立即填充),需执行 REFRESH MATERIALIZED VIEW 或等待定时刷新。
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- ============================================================
|
||||
-- 1. 助教日度明细物化视图(mv_dws_assistant_daily_detail_l1..l4)
|
||||
-- ============================================================
|
||||
|
||||
-- L1:昨日 + 今日(营业日口径)
|
||||
DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_assistant_daily_detail_l1;
|
||||
CREATE MATERIALIZED VIEW dws.mv_dws_assistant_daily_detail_l1 AS
|
||||
SELECT * FROM dws.dws_assistant_daily_detail
|
||||
WHERE stat_date >= (dws.biz_date(NOW()) - '1 day'::interval)
|
||||
WITH DATA;
|
||||
|
||||
-- L2:近 30 天(营业日口径)
|
||||
DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_assistant_daily_detail_l2;
|
||||
CREATE MATERIALIZED VIEW dws.mv_dws_assistant_daily_detail_l2 AS
|
||||
SELECT * FROM dws.dws_assistant_daily_detail
|
||||
WHERE stat_date >= (dws.biz_date(NOW()) - '30 days'::interval)
|
||||
WITH DATA;
|
||||
|
||||
-- L3:近 90 天(营业日口径)
|
||||
DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_assistant_daily_detail_l3;
|
||||
CREATE MATERIALIZED VIEW dws.mv_dws_assistant_daily_detail_l3 AS
|
||||
SELECT * FROM dws.dws_assistant_daily_detail
|
||||
WHERE stat_date >= (dws.biz_date(NOW()) - '90 days'::interval)
|
||||
WITH DATA;
|
||||
|
||||
-- L4:近 6 个月(不含当月,营业日口径)
|
||||
DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_assistant_daily_detail_l4;
|
||||
CREATE MATERIALIZED VIEW dws.mv_dws_assistant_daily_detail_l4 AS
|
||||
SELECT * FROM dws.dws_assistant_daily_detail
|
||||
WHERE stat_date >= (date_trunc('month', dws.biz_date(NOW())::timestamp with time zone) - '6 mons'::interval)
|
||||
AND stat_date < date_trunc('month', dws.biz_date(NOW())::timestamp with time zone)
|
||||
WITH DATA;
|
||||
|
||||
-- ============================================================
|
||||
-- 2. 财务日度汇总物化视图(mv_dws_finance_daily_summary_l1..l4)
|
||||
-- ============================================================
|
||||
|
||||
-- L1:昨日 + 今日(营业日口径)
|
||||
DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_finance_daily_summary_l1;
|
||||
CREATE MATERIALIZED VIEW dws.mv_dws_finance_daily_summary_l1 AS
|
||||
SELECT * FROM dws.dws_finance_daily_summary
|
||||
WHERE stat_date >= (dws.biz_date(NOW()) - '1 day'::interval)
|
||||
WITH DATA;
|
||||
|
||||
-- L2:近 30 天(营业日口径)
|
||||
DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_finance_daily_summary_l2;
|
||||
CREATE MATERIALIZED VIEW dws.mv_dws_finance_daily_summary_l2 AS
|
||||
SELECT * FROM dws.dws_finance_daily_summary
|
||||
WHERE stat_date >= (dws.biz_date(NOW()) - '30 days'::interval)
|
||||
WITH DATA;
|
||||
|
||||
-- L3:近 90 天(营业日口径)
|
||||
DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_finance_daily_summary_l3;
|
||||
CREATE MATERIALIZED VIEW dws.mv_dws_finance_daily_summary_l3 AS
|
||||
SELECT * FROM dws.dws_finance_daily_summary
|
||||
WHERE stat_date >= (dws.biz_date(NOW()) - '90 days'::interval)
|
||||
WITH DATA;
|
||||
|
||||
-- L4:近 6 个月(不含当月,营业日口径)
|
||||
DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_finance_daily_summary_l4;
|
||||
CREATE MATERIALIZED VIEW dws.mv_dws_finance_daily_summary_l4 AS
|
||||
SELECT * FROM dws.dws_finance_daily_summary
|
||||
WHERE stat_date >= (date_trunc('month', dws.biz_date(NOW())::timestamp with time zone) - '6 mons'::interval)
|
||||
AND stat_date < date_trunc('month', dws.biz_date(NOW())::timestamp with time zone)
|
||||
WITH DATA;
|
||||
|
||||
-- ============================================================
|
||||
-- 3. 重建物化视图索引
|
||||
-- ============================================================
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_mv_assistant_daily_l1
|
||||
ON dws.mv_dws_assistant_daily_detail_l1 USING btree (site_id, stat_date, assistant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_mv_assistant_daily_l2
|
||||
ON dws.mv_dws_assistant_daily_detail_l2 USING btree (site_id, stat_date, assistant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_mv_assistant_daily_l3
|
||||
ON dws.mv_dws_assistant_daily_detail_l3 USING btree (site_id, stat_date, assistant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_mv_assistant_daily_l4
|
||||
ON dws.mv_dws_assistant_daily_detail_l4 USING btree (site_id, stat_date, assistant_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_mv_finance_daily_l1
|
||||
ON dws.mv_dws_finance_daily_summary_l1 USING btree (site_id, stat_date);
|
||||
CREATE INDEX IF NOT EXISTS idx_mv_finance_daily_l2
|
||||
ON dws.mv_dws_finance_daily_summary_l2 USING btree (site_id, stat_date);
|
||||
CREATE INDEX IF NOT EXISTS idx_mv_finance_daily_l3
|
||||
ON dws.mv_dws_finance_daily_summary_l3 USING btree (site_id, stat_date);
|
||||
CREATE INDEX IF NOT EXISTS idx_mv_finance_daily_l4
|
||||
ON dws.mv_dws_finance_daily_summary_l4 USING btree (site_id, stat_date);
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- 验证 SQL(迁移后执行):
|
||||
-- 1. 确认函数存在
|
||||
-- SELECT dws.biz_date(NOW());
|
||||
--
|
||||
-- 2. 确认 8 个物化视图已重建
|
||||
-- SELECT schemaname, matviewname FROM pg_matviews
|
||||
-- WHERE schemaname = 'dws' AND matviewname LIKE 'mv_dws_%'
|
||||
-- ORDER BY matviewname;
|
||||
--
|
||||
-- 3. 确认索引已创建
|
||||
-- SELECT indexname FROM pg_indexes
|
||||
-- WHERE schemaname = 'dws' AND tablename LIKE 'mv_dws_%'
|
||||
-- ORDER BY indexname;
|
||||
--
|
||||
-- 4. 确认视图定义中包含 biz_date
|
||||
-- SELECT matviewname, definition FROM pg_matviews
|
||||
-- WHERE schemaname = 'dws' AND matviewname LIKE 'mv_dws_%'
|
||||
-- AND definition LIKE '%biz_date%';
|
||||
|
||||
-- 回滚(恢复为自然日口径):
|
||||
-- BEGIN;
|
||||
-- DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_assistant_daily_detail_l1;
|
||||
-- DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_assistant_daily_detail_l2;
|
||||
-- DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_assistant_daily_detail_l3;
|
||||
-- DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_assistant_daily_detail_l4;
|
||||
-- DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_finance_daily_summary_l1;
|
||||
-- DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_finance_daily_summary_l2;
|
||||
-- DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_finance_daily_summary_l3;
|
||||
-- DROP MATERIALIZED VIEW IF EXISTS dws.mv_dws_finance_daily_summary_l4;
|
||||
-- -- 然后用 scripts/migrate/migrate_finalize.py 中的原始定义重建
|
||||
-- COMMIT;
|
||||
@@ -1,63 +0,0 @@
|
||||
-- =============================================================================
|
||||
-- 迁移:dws_assistant_order_contribution.tenant_id INTEGER → BIGINT
|
||||
-- 原因:飞球 tenant_id 值域(如 2790683160709957)远超 int4 上限(~21 亿)
|
||||
-- 依赖:app.v_dws_assistant_order_contribution 视图需先 DROP 再重建
|
||||
-- 日期:2026-03-03
|
||||
-- 目标库:etl_feiqiu / test_etl_feiqiu
|
||||
-- =============================================================================
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 1. DROP 依赖的 RLS 视图
|
||||
DROP VIEW IF EXISTS app.v_dws_assistant_order_contribution CASCADE;
|
||||
|
||||
-- 2. ALTER 列类型
|
||||
ALTER TABLE dws.dws_assistant_order_contribution
|
||||
ALTER COLUMN tenant_id TYPE bigint;
|
||||
|
||||
-- 3. 重建 RLS 视图
|
||||
CREATE OR REPLACE VIEW app.v_dws_assistant_order_contribution AS
|
||||
SELECT * FROM dws.dws_assistant_order_contribution
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
GRANT SELECT ON app.v_dws_assistant_order_contribution TO app_reader;
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- =============================================================================
|
||||
-- 回滚脚本
|
||||
-- =============================================================================
|
||||
-- BEGIN;
|
||||
-- DROP VIEW IF EXISTS app.v_dws_assistant_order_contribution CASCADE;
|
||||
-- ALTER TABLE dws.dws_assistant_order_contribution ALTER COLUMN tenant_id TYPE integer;
|
||||
-- CREATE OR REPLACE VIEW app.v_dws_assistant_order_contribution AS
|
||||
-- SELECT * FROM dws.dws_assistant_order_contribution
|
||||
-- WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
-- GRANT SELECT ON app.v_dws_assistant_order_contribution TO app_reader;
|
||||
-- COMMIT;
|
||||
|
||||
-- =============================================================================
|
||||
-- 验证 SQL
|
||||
-- =============================================================================
|
||||
-- 1. 确认列类型已变更
|
||||
-- SELECT column_name, data_type, udt_name
|
||||
-- FROM information_schema.columns
|
||||
-- WHERE table_schema = 'dws'
|
||||
-- AND table_name = 'dws_assistant_order_contribution'
|
||||
-- AND column_name = 'tenant_id';
|
||||
-- 预期:data_type = 'bigint', udt_name = 'int8'
|
||||
|
||||
-- 2. 确认视图已重建
|
||||
-- SELECT table_schema, table_name
|
||||
-- FROM information_schema.views
|
||||
-- WHERE table_schema = 'app'
|
||||
-- AND table_name = 'v_dws_assistant_order_contribution';
|
||||
-- 预期:1 行
|
||||
|
||||
-- 3. 确认视图中 tenant_id 类型正确
|
||||
-- SELECT column_name, data_type
|
||||
-- FROM information_schema.columns
|
||||
-- WHERE table_schema = 'app'
|
||||
-- AND table_name = 'v_dws_assistant_order_contribution'
|
||||
-- AND column_name = 'tenant_id';
|
||||
-- 预期:data_type = 'bigint'
|
||||
@@ -1,27 +0,0 @@
|
||||
-- =============================================================================
|
||||
-- 迁移脚本:dim_groupbuy_package_ex 新增团购详情字段
|
||||
-- 日期:2026-03-05
|
||||
-- 说明:从团购详情接口(QueryPackageCouponInfo)提取的 4 个 JSONB 字段,
|
||||
-- 补充可用台区、助教服务、关联门店等维度信息
|
||||
-- 需求:需求 4 验收标准 1
|
||||
-- =============================================================================
|
||||
|
||||
ALTER TABLE dwd.dim_groupbuy_package_ex
|
||||
ADD COLUMN IF NOT EXISTS table_area_ids JSONB,
|
||||
ADD COLUMN IF NOT EXISTS table_area_names JSONB,
|
||||
ADD COLUMN IF NOT EXISTS assistant_services JSONB,
|
||||
ADD COLUMN IF NOT EXISTS groupon_site_infos JSONB;
|
||||
|
||||
COMMENT ON COLUMN dwd.dim_groupbuy_package_ex.table_area_ids IS '可用台区 ID 列表(来自详情接口 tableAreaId)';
|
||||
COMMENT ON COLUMN dwd.dim_groupbuy_package_ex.table_area_names IS '可用台区名称列表(来自详情接口 tableAreaNameList)';
|
||||
COMMENT ON COLUMN dwd.dim_groupbuy_package_ex.assistant_services IS '助教服务关联(来自详情接口 packageCouponAssistants)';
|
||||
COMMENT ON COLUMN dwd.dim_groupbuy_package_ex.groupon_site_infos IS '关联门店信息(来自详情接口 grouponSiteInfos)';
|
||||
|
||||
-- =============================================================================
|
||||
-- 回滚脚本(如需撤销)
|
||||
-- ALTER TABLE dwd.dim_groupbuy_package_ex
|
||||
-- DROP COLUMN IF EXISTS table_area_ids,
|
||||
-- DROP COLUMN IF EXISTS table_area_names,
|
||||
-- DROP COLUMN IF EXISTS assistant_services,
|
||||
-- DROP COLUMN IF EXISTS groupon_site_infos;
|
||||
-- =============================================================================
|
||||
@@ -1,102 +0,0 @@
|
||||
-- =============================================================================
|
||||
-- 迁移:cfg_area_category 新增字段 + VIP 包厢拆分 + 显示名称更新
|
||||
-- 日期:2026-03-07
|
||||
-- 说明:
|
||||
-- 1. 新增 source_table_name、display_name、short_name 三个字段
|
||||
-- 2. 删除 BILLIARD_VIP 类型,VIP包厢默认归 BILLIARD,V5 单独归 SNOOKER
|
||||
-- 3. 更新四大项目类型的 display_name 和 short_name
|
||||
-- 4. 更新模糊匹配规则(%VIP% 改为 BILLIARD)
|
||||
-- 回滚:见文件末尾 ROLLBACK 部分
|
||||
-- =============================================================================
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 1. 新增字段
|
||||
ALTER TABLE dws.cfg_area_category
|
||||
ADD COLUMN IF NOT EXISTS source_table_name VARCHAR(100) DEFAULT NULL,
|
||||
ADD COLUMN IF NOT EXISTS display_name VARCHAR(50) DEFAULT NULL,
|
||||
ADD COLUMN IF NOT EXISTS short_name VARCHAR(20) DEFAULT NULL;
|
||||
|
||||
-- 1.1 唯一约束从 (source_area_name) 改为 (source_area_name, source_table_name)
|
||||
-- 支持同一台区下按台桌名称细分映射
|
||||
ALTER TABLE dws.cfg_area_category DROP CONSTRAINT IF EXISTS uk_cfg_area_category;
|
||||
CREATE UNIQUE INDEX uk_cfg_area_category
|
||||
ON dws.cfg_area_category (source_area_name, COALESCE(source_table_name, ''));
|
||||
|
||||
|
||||
-- 2. 为现有记录填充 display_name 和 short_name
|
||||
UPDATE dws.cfg_area_category SET display_name = '🎱 中式/追分', short_name = '🎱'
|
||||
WHERE category_code = 'BILLIARD';
|
||||
UPDATE dws.cfg_area_category SET display_name = '斯诺克', short_name = '斯'
|
||||
WHERE category_code = 'SNOOKER';
|
||||
UPDATE dws.cfg_area_category SET display_name = '🀄 麻将/棋牌', short_name = '🀄'
|
||||
WHERE category_code = 'MAHJONG';
|
||||
UPDATE dws.cfg_area_category SET display_name = '🎤 团建/K歌', short_name = '🎤'
|
||||
WHERE category_code = 'KTV';
|
||||
UPDATE dws.cfg_area_category SET display_name = '补时长', short_name = '补'
|
||||
WHERE category_code = 'SPECIAL';
|
||||
UPDATE dws.cfg_area_category SET display_name = '其他', short_name = '他'
|
||||
WHERE category_code = 'OTHER';
|
||||
|
||||
-- 3. VIP包厢拆分:将原 BILLIARD_VIP 精确匹配改为 BILLIARD
|
||||
UPDATE dws.cfg_area_category
|
||||
SET category_code = 'BILLIARD',
|
||||
category_name = '🎱 中式/追分',
|
||||
display_name = '🎱 中式/追分',
|
||||
short_name = '🎱',
|
||||
description = '台球VIP包厢(V1-V4中八)→ 归入中式/追分',
|
||||
updated_at = NOW()
|
||||
WHERE source_area_name = 'VIP包厢' AND match_type = 'EXACT';
|
||||
|
||||
-- 4. 新增 V5 → SNOOKER 的台桌级映射(优先级高于区域级)
|
||||
INSERT INTO dws.cfg_area_category (
|
||||
source_area_name, source_table_name, category_code, category_name,
|
||||
display_name, short_name,
|
||||
match_type, match_priority, is_active, description
|
||||
) VALUES (
|
||||
'VIP包厢', 'V5', 'SNOOKER', '斯诺克',
|
||||
'斯诺克', '斯',
|
||||
'EXACT', 5, TRUE,
|
||||
'VIP包厢V5台→斯诺克(台桌级精确匹配,优先级高于区域级)'
|
||||
);
|
||||
|
||||
-- 5. 模糊匹配 %VIP% 改为 BILLIARD(原为 BILLIARD_VIP)
|
||||
UPDATE dws.cfg_area_category
|
||||
SET category_code = 'BILLIARD',
|
||||
category_name = '🎱 中式/追分',
|
||||
display_name = '🎱 中式/追分',
|
||||
short_name = '🎱',
|
||||
description = '模糊匹配:包含"VIP"的区域→归入中式/追分',
|
||||
updated_at = NOW()
|
||||
WHERE source_area_name = '%VIP%' AND match_type = 'LIKE';
|
||||
|
||||
-- 6. 更新所有分类的 category_name 为新显示名
|
||||
UPDATE dws.cfg_area_category SET category_name = '🎱 中式/追分', updated_at = NOW()
|
||||
WHERE category_code = 'BILLIARD' AND category_name != '🎱 中式/追分';
|
||||
UPDATE dws.cfg_area_category SET category_name = '斯诺克', updated_at = NOW()
|
||||
WHERE category_code = 'SNOOKER' AND category_name != '斯诺克';
|
||||
UPDATE dws.cfg_area_category SET category_name = '🀄 麻将/棋牌', updated_at = NOW()
|
||||
WHERE category_code = 'MAHJONG' AND category_name != '🀄 麻将/棋牌';
|
||||
UPDATE dws.cfg_area_category SET category_name = '🎤 团建/K歌', updated_at = NOW()
|
||||
WHERE category_code = 'KTV' AND category_name != '🎤 团建/K歌';
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- =============================================================================
|
||||
-- ROLLBACK(如需回滚,手动执行以下语句)
|
||||
-- =============================================================================
|
||||
-- BEGIN;
|
||||
-- DELETE FROM dws.cfg_area_category WHERE source_table_name = 'V5';
|
||||
-- UPDATE dws.cfg_area_category SET category_code = 'BILLIARD_VIP', category_name = '台球VIP',
|
||||
-- description = '台球VIP:VIP包厢(4台)- V1-V4中八, V5斯诺克'
|
||||
-- WHERE source_area_name = 'VIP包厢' AND match_type = 'EXACT';
|
||||
-- UPDATE dws.cfg_area_category SET category_code = 'BILLIARD_VIP', category_name = '台球VIP'
|
||||
-- WHERE source_area_name = '%VIP%' AND match_type = 'LIKE';
|
||||
-- UPDATE dws.cfg_area_category SET category_name = '台球散台' WHERE category_code = 'BILLIARD';
|
||||
-- UPDATE dws.cfg_area_category SET category_name = '斯诺克' WHERE category_code = 'SNOOKER';
|
||||
-- UPDATE dws.cfg_area_category SET category_name = '麻将棋牌' WHERE category_code = 'MAHJONG';
|
||||
-- UPDATE dws.cfg_area_category SET category_name = 'K歌娱乐' WHERE category_code = 'KTV';
|
||||
-- ALTER TABLE dws.cfg_area_category DROP COLUMN IF EXISTS source_table_name;
|
||||
-- ALTER TABLE dws.cfg_area_category DROP COLUMN IF EXISTS display_name;
|
||||
-- ALTER TABLE dws.cfg_area_category DROP COLUMN IF EXISTS short_name;
|
||||
-- COMMIT;
|
||||
@@ -1,95 +0,0 @@
|
||||
-- =============================================================================
|
||||
-- 迁移脚本:创建项目标签表
|
||||
-- 日期:2026-03-07
|
||||
-- 说明:新建 dws_assistant_project_tag 和 dws_member_project_tag 两张表,
|
||||
-- 存储助教和客户按项目类型的时长占比标签
|
||||
-- 依赖:cfg_area_category(2026-03-07 已更新,含 display_name/short_name)
|
||||
-- =============================================================================
|
||||
|
||||
-- 1. 助教项目标签表
|
||||
CREATE TABLE IF NOT EXISTS dws.dws_assistant_project_tag (
|
||||
id BIGSERIAL NOT NULL,
|
||||
site_id BIGINT NOT NULL,
|
||||
tenant_id BIGINT NOT NULL,
|
||||
assistant_id BIGINT NOT NULL,
|
||||
time_window VARCHAR(40) NOT NULL, -- TimeWindow 枚举值
|
||||
category_code VARCHAR(30) NOT NULL, -- BILLIARD/SNOOKER/MAHJONG/KTV
|
||||
category_name VARCHAR(50) NOT NULL, -- 显示名称(如 🎱 中式/追分)
|
||||
short_name VARCHAR(10) NOT NULL, -- 简写(如 🎱)
|
||||
duration_seconds BIGINT NOT NULL DEFAULT 0, -- 该项目总工作时长(秒)
|
||||
total_seconds BIGINT NOT NULL DEFAULT 0, -- 所有四大项目总时长(秒)
|
||||
percentage NUMERIC(5,4) NOT NULL DEFAULT 0, -- 占比(0~1)
|
||||
is_tagged BOOLEAN NOT NULL DEFAULT FALSE, -- 占比≥25% 则为 TRUE
|
||||
computed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT pk_dws_assistant_project_tag PRIMARY KEY (id),
|
||||
CONSTRAINT uk_dws_assistant_project_tag
|
||||
UNIQUE (site_id, assistant_id, time_window, category_code)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE dws.dws_assistant_project_tag IS '助教项目标签:按时间窗口计算各项目时长占比,≥25%分配标签';
|
||||
COMMENT ON COLUMN dws.dws_assistant_project_tag.time_window IS '时间窗口:THIS_MONTH/THIS_QUARTER/LAST_MONTH/LAST_3_MONTHS_EXCL_CURRENT/LAST_QUARTER/LAST_6_MONTHS';
|
||||
COMMENT ON COLUMN dws.dws_assistant_project_tag.is_tagged IS '占比≥0.25时为TRUE,表示该助教拥有此项目标签';
|
||||
|
||||
-- 2. 客户项目标签表
|
||||
CREATE TABLE IF NOT EXISTS dws.dws_member_project_tag (
|
||||
id BIGSERIAL NOT NULL,
|
||||
site_id BIGINT NOT NULL,
|
||||
tenant_id BIGINT NOT NULL,
|
||||
member_id BIGINT NOT NULL,
|
||||
time_window VARCHAR(40) NOT NULL, -- TimeWindow 枚举值
|
||||
category_code VARCHAR(30) NOT NULL, -- BILLIARD/SNOOKER/MAHJONG/KTV
|
||||
category_name VARCHAR(50) NOT NULL, -- 显示名称
|
||||
short_name VARCHAR(10) NOT NULL, -- 简写
|
||||
duration_seconds BIGINT NOT NULL DEFAULT 0, -- 该项目总计费时长(秒)
|
||||
total_seconds BIGINT NOT NULL DEFAULT 0, -- 所有四大项目总时长(秒)
|
||||
percentage NUMERIC(5,4) NOT NULL DEFAULT 0, -- 占比(0~1)
|
||||
is_tagged BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
computed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT pk_dws_member_project_tag PRIMARY KEY (id),
|
||||
CONSTRAINT uk_dws_member_project_tag
|
||||
UNIQUE (site_id, member_id, time_window, category_code)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE dws.dws_member_project_tag IS '客户项目标签:按时间窗口计算各项目消费时长占比,≥25%分配标签';
|
||||
COMMENT ON COLUMN dws.dws_member_project_tag.time_window IS '时间窗口:LAST_30_DAYS/LAST_60_DAYS';
|
||||
COMMENT ON COLUMN dws.dws_member_project_tag.is_tagged IS '占比≥0.25时为TRUE,表示该客户拥有此项目标签';
|
||||
|
||||
-- 3. 索引(加速看板查询:按 site_id + time_window 筛选 is_tagged=TRUE 的标签)
|
||||
CREATE INDEX IF NOT EXISTS idx_apt_site_window_tagged
|
||||
ON dws.dws_assistant_project_tag (site_id, time_window)
|
||||
WHERE is_tagged = TRUE;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_mpt_site_window_tagged
|
||||
ON dws.dws_member_project_tag (site_id, time_window)
|
||||
WHERE is_tagged = TRUE;
|
||||
|
||||
-- =============================================================================
|
||||
-- 验证
|
||||
-- =============================================================================
|
||||
DO $$
|
||||
DECLARE
|
||||
v_apt_exists BOOLEAN;
|
||||
v_mpt_exists BOOLEAN;
|
||||
BEGIN
|
||||
SELECT EXISTS(SELECT 1 FROM information_schema.tables
|
||||
WHERE table_schema = 'dws' AND table_name = 'dws_assistant_project_tag')
|
||||
INTO v_apt_exists;
|
||||
|
||||
SELECT EXISTS(SELECT 1 FROM information_schema.tables
|
||||
WHERE table_schema = 'dws' AND table_name = 'dws_member_project_tag')
|
||||
INTO v_mpt_exists;
|
||||
|
||||
IF NOT v_apt_exists THEN
|
||||
RAISE EXCEPTION 'dws_assistant_project_tag 创建失败';
|
||||
END IF;
|
||||
IF NOT v_mpt_exists THEN
|
||||
RAISE EXCEPTION 'dws_member_project_tag 创建失败';
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '✅ 两张项目标签表创建成功';
|
||||
END;
|
||||
$$;
|
||||
@@ -1,67 +0,0 @@
|
||||
-- 迁移:统一 DWS 层储值卡/充值卡支付字段命名
|
||||
-- 日期:2026-03-07
|
||||
-- 关联:账务构成排查发现 cash_card_pay/cash_card_consume 语义歧义
|
||||
-- cash_card_pay 取 balance_amount(含赠送卡),cash_card_consume 取 recharge_card_amount(仅现金卡)
|
||||
-- 幂等:RENAME + ADD 均为幂等操作(已存在则跳过)
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- =============================================================================
|
||||
-- 1. dws_member_visit_detail:cash_card_pay → balance_pay + 新增 recharge_card_pay
|
||||
-- =============================================================================
|
||||
|
||||
-- 1a. 重命名 cash_card_pay → balance_pay(储值卡总额 = recharge + gift)
|
||||
ALTER TABLE dws.dws_member_visit_detail
|
||||
RENAME COLUMN cash_card_pay TO balance_pay;
|
||||
|
||||
-- 1b. 新增 recharge_card_pay(现金充值卡支付,balance_pay 的子项)
|
||||
ALTER TABLE dws.dws_member_visit_detail
|
||||
ADD COLUMN IF NOT EXISTS recharge_card_pay NUMERIC(12,2) NOT NULL DEFAULT 0;
|
||||
|
||||
-- 1c. 回填 recharge_card_pay = balance_pay - gift_card_pay
|
||||
UPDATE dws.dws_member_visit_detail
|
||||
SET recharge_card_pay = balance_pay - gift_card_pay
|
||||
WHERE recharge_card_pay = 0 AND balance_pay > 0;
|
||||
|
||||
-- =============================================================================
|
||||
-- 2. dws_finance_daily_summary:cash_card_consume → recharge_card_consume
|
||||
-- =============================================================================
|
||||
|
||||
ALTER TABLE dws.dws_finance_daily_summary
|
||||
RENAME COLUMN cash_card_consume TO recharge_card_consume;
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- =============================================================================
|
||||
-- 验证 SQL
|
||||
-- =============================================================================
|
||||
-- 1. 确认 dws_member_visit_detail 字段存在
|
||||
-- SELECT column_name FROM information_schema.columns
|
||||
-- WHERE table_schema = 'dws' AND table_name = 'dws_member_visit_detail'
|
||||
-- AND column_name IN ('balance_pay', 'recharge_card_pay', 'gift_card_pay')
|
||||
-- ORDER BY column_name;
|
||||
-- 预期:3 行(balance_pay, gift_card_pay, recharge_card_pay)
|
||||
|
||||
-- 2. 确认 cash_card_pay 已不存在
|
||||
-- SELECT column_name FROM information_schema.columns
|
||||
-- WHERE table_schema = 'dws' AND table_name = 'dws_member_visit_detail'
|
||||
-- AND column_name = 'cash_card_pay';
|
||||
-- 预期:0 行
|
||||
|
||||
-- 3. 确认 dws_finance_daily_summary 字段重命名
|
||||
-- SELECT column_name FROM information_schema.columns
|
||||
-- WHERE table_schema = 'dws' AND table_name = 'dws_finance_daily_summary'
|
||||
-- AND column_name IN ('recharge_card_consume', 'gift_card_consume', 'card_consume_total');
|
||||
-- 预期:3 行
|
||||
|
||||
-- 4. 确认 cash_card_consume 已不存在
|
||||
-- SELECT column_name FROM information_schema.columns
|
||||
-- WHERE table_schema = 'dws' AND table_name = 'dws_finance_daily_summary'
|
||||
-- AND column_name = 'cash_card_consume';
|
||||
-- 预期:0 行
|
||||
|
||||
-- 5. 验证 recharge_card_pay 回填正确(balance_pay = recharge_card_pay + gift_card_pay)
|
||||
-- SELECT COUNT(*) AS mismatch_count
|
||||
-- FROM dws.dws_member_visit_detail
|
||||
-- WHERE ABS(balance_pay - recharge_card_pay - gift_card_pay) > 0.01;
|
||||
-- 预期:0
|
||||
@@ -1,58 +0,0 @@
|
||||
-- 迁移:DWS 层 ratio/margin/multiplier 字段精度扩展
|
||||
-- 原因:numeric(5,4) 只能存 ±0.9999,当比率 ≥ 1 或 < -1 时溢出(P1 已爆 gross_margin)
|
||||
-- 日期:2026-03-01
|
||||
-- 注意:需先 DROP 依赖视图,ALTER 后重建
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 1. DROP 依赖视图(app schema 的 RLS 视图)
|
||||
DROP VIEW IF EXISTS app.v_cfg_performance_tier CASCADE;
|
||||
DROP VIEW IF EXISTS app.v_dws_assistant_finance_analysis CASCADE;
|
||||
DROP VIEW IF EXISTS app.v_dws_assistant_recharge_commission CASCADE;
|
||||
DROP VIEW IF EXISTS app.v_dws_assistant_salary_calc CASCADE;
|
||||
DROP VIEW IF EXISTS app.v_dws_finance_discount_detail CASCADE;
|
||||
DROP VIEW IF EXISTS app.v_dws_finance_income_structure CASCADE;
|
||||
DROP VIEW IF EXISTS app.v_dws_member_assistant_intimacy CASCADE;
|
||||
|
||||
-- 2. ALTER 列类型:numeric(5,4)/numeric(6,4) → numeric(7,4)
|
||||
ALTER TABLE dws.cfg_performance_tier
|
||||
ALTER COLUMN bonus_deduction_ratio TYPE numeric(7,4);
|
||||
ALTER TABLE dws.dws_assistant_finance_analysis
|
||||
ALTER COLUMN gross_margin TYPE numeric(7,4);
|
||||
ALTER TABLE dws.dws_assistant_recharge_commission
|
||||
ALTER COLUMN commission_ratio TYPE numeric(7,4);
|
||||
ALTER TABLE dws.dws_assistant_salary_calc
|
||||
ALTER COLUMN bonus_deduction_ratio TYPE numeric(7,4);
|
||||
ALTER TABLE dws.dws_finance_discount_detail
|
||||
ALTER COLUMN discount_ratio TYPE numeric(7,4);
|
||||
ALTER TABLE dws.dws_finance_income_structure
|
||||
ALTER COLUMN income_ratio TYPE numeric(7,4);
|
||||
ALTER TABLE dws.dws_member_assistant_intimacy
|
||||
ALTER COLUMN burst_multiplier TYPE numeric(7,4);
|
||||
|
||||
-- 3. 重建视图(使用 pg_get_viewdef 保存的原始定义)
|
||||
-- 注意:实际执行时应从 _p1_migrate_with_views.py 自动保存/重建
|
||||
-- 以下为手动重建模板,视图定义为 SELECT * FROM dws.xxx WHERE site_id = ...
|
||||
CREATE OR REPLACE VIEW app.v_cfg_performance_tier AS
|
||||
SELECT * FROM dws.cfg_performance_tier
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
CREATE OR REPLACE VIEW app.v_dws_assistant_finance_analysis AS
|
||||
SELECT * FROM dws.dws_assistant_finance_analysis
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
CREATE OR REPLACE VIEW app.v_dws_assistant_recharge_commission AS
|
||||
SELECT * FROM dws.dws_assistant_recharge_commission
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
CREATE OR REPLACE VIEW app.v_dws_assistant_salary_calc AS
|
||||
SELECT * FROM dws.dws_assistant_salary_calc
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
CREATE OR REPLACE VIEW app.v_dws_finance_discount_detail AS
|
||||
SELECT * FROM dws.dws_finance_discount_detail
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
CREATE OR REPLACE VIEW app.v_dws_finance_income_structure AS
|
||||
SELECT * FROM dws.dws_finance_income_structure
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
CREATE OR REPLACE VIEW app.v_dws_member_assistant_intimacy AS
|
||||
SELECT * FROM dws.dws_member_assistant_intimacy
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
|
||||
COMMIT;
|
||||
@@ -1,28 +0,0 @@
|
||||
-- 回滚:DWS 层 ratio/margin/multiplier 字段精度还原
|
||||
-- 注意:如果已有数据超出原精度范围,回滚会失败,需先清理数据
|
||||
-- 日期:2026-03-01
|
||||
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE dws.cfg_performance_tier
|
||||
ALTER COLUMN bonus_deduction_ratio TYPE numeric(5,4);
|
||||
|
||||
ALTER TABLE dws.dws_assistant_finance_analysis
|
||||
ALTER COLUMN gross_margin TYPE numeric(5,4);
|
||||
|
||||
ALTER TABLE dws.dws_assistant_recharge_commission
|
||||
ALTER COLUMN commission_ratio TYPE numeric(5,4);
|
||||
|
||||
ALTER TABLE dws.dws_assistant_salary_calc
|
||||
ALTER COLUMN bonus_deduction_ratio TYPE numeric(5,4);
|
||||
|
||||
ALTER TABLE dws.dws_finance_discount_detail
|
||||
ALTER COLUMN discount_ratio TYPE numeric(5,4);
|
||||
|
||||
ALTER TABLE dws.dws_finance_income_structure
|
||||
ALTER COLUMN income_ratio TYPE numeric(5,4);
|
||||
|
||||
ALTER TABLE dws.dws_member_spending_power_index
|
||||
ALTER COLUMN burst_multiplier TYPE numeric(6,4);
|
||||
|
||||
COMMIT;
|
||||
@@ -1,22 +0,0 @@
|
||||
-- 迁移:ods.goods_stock_summary 加 siteid 列
|
||||
-- 原因:API 返回记录不含 siteId,但 DWD 层需要 site_id 做门店隔离
|
||||
-- ODS 入库时从 app.store_id 注入
|
||||
-- 日期:2026-03-01
|
||||
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE ods.goods_stock_summary
|
||||
ADD COLUMN IF NOT EXISTS siteid bigint;
|
||||
|
||||
-- 回填已有数据(单门店部署,所有记录属于同一 store_id)
|
||||
-- 实际 store_id 值需从 .env 的 STORE_ID 获取,此处用子查询从 goods_stock_movements 推断
|
||||
UPDATE ods.goods_stock_summary s
|
||||
SET siteid = (
|
||||
SELECT DISTINCT m.siteid
|
||||
FROM ods.goods_stock_movements m
|
||||
WHERE m.siteid IS NOT NULL
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE s.siteid IS NULL;
|
||||
|
||||
COMMIT;
|
||||
Reference in New Issue
Block a user