#!/bin/bash # refresh_materialized_views.sh # 数据导入后刷新所有物化视图并更新费用物化表 # 用法: bash scripts/refresh_materialized_views.sh [YYYY-MM-DD] # 示例: bash scripts/refresh_materialized_views.sh 2026-04-01 set -e MONTH_START="${1:-$(date -u +%Y-%m-01)}" DB_HOST="${DB_HOST:-localhost}" DB_PORT="${DB_PORT:-5432}" DB_USER="${DB_USER:-freedak}" DB_NAME="${DB_NAME:-bill_query}" echo "==========================================" echo " 刷新物化视图" echo " 月份: ${MONTH_START}" echo " 数据库: ${DB_NAME}@${DB_HOST}:${DB_PORT}" echo "==========================================" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" < 0 THEN discount_total::numeric / consumption * 100 ELSE 0 END)::numeric, 2) AS discount_rate_pct, 0 AS theoretical_margin_pct, 0 AS member_bills, 0 AS member_share_pct FROM analytics.bill_fact WHERE closed_at >= '${MONTH_START}' AND closed_at < ('${MONTH_START}'::date + interval '1 month') GROUP BY date_trunc('month', closed_at); SELECT 'mv_overview_monthly updated' AS status; -- 第二层:门店评估 REFRESH MATERIALIZED VIEW analytics.mv_store_risk_rating_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_theoretical_actual_cost_monthly; REFRESH MATERIALIZED VIEW analytics.mv_daily_revenue; SELECT 'core MVs refreshed' AS status; -- 第三层:菜品分析 REFRESH MATERIALIZED VIEW analytics.mv_dish_sku_abc_monthly; REFRESH MATERIALIZED VIEW analytics.mv_dish_sku_summary_monthly; REFRESH MATERIALIZED VIEW analytics.mv_dish_store_summary_monthly; REFRESH MATERIALIZED VIEW analytics.mv_dish_basket_monthly; REFRESH MATERIALIZED VIEW analytics.mv_dish_pair_summary_monthly; SELECT 'dish MVs refreshed' AS status; -- 第四层:门店深度分析 REFRESH MATERIALIZED VIEW analytics.mv_store_action_priority_deep_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_area_efficiency_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_benchmark_composite_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_category_mix_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_deep_diagnosis_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_member_opportunity_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_overlap_risk_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_platform_economics_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_site_profile_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_site_replication_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_repeat_summary_monthly; SELECT 'store deep MVs refreshed' AS status; -- 第五层:区域与选址 REFRESH MATERIALIZED VIEW analytics.mv_district_site_benchmark_monthly; REFRESH MATERIALIZED VIEW analytics.mv_site_segment_benchmark_monthly; SELECT 'region MVs refreshed' AS status; -- 库存成本 REFRESH MATERIALIZED VIEW analytics.mv_inventory_cost_classified_monthly; SELECT 'inventory MV refreshed' AS status; -- 费用物化表(从视图写入) DELETE FROM analytics.mv_store_operating_expense_monthly WHERE report_month = '${MONTH_START}'; INSERT INTO analytics.mv_store_operating_expense_monthly SELECT * FROM analytics.v_store_operating_expense_monthly WHERE report_month = '${MONTH_START}'; SELECT 'expense table updated' AS status; -- 验证 SELECT '=== 数据一致性验证 ===' AS header; SELECT 'bill_fact' AS source, count(DISTINCT store_code) AS stores, round(sum(received_total)::numeric,2) AS received FROM analytics.bill_fact WHERE closed_at >= '${MONTH_START}' AND closed_at < ('${MONTH_START}'::date + interval '1 month') UNION ALL SELECT 'risk_rating', count(*), round(sum(received)::numeric,2) FROM analytics.mv_store_risk_rating_monthly WHERE month_start = '${MONTH_START}' UNION ALL SELECT 'theo_cost', count(*), round(sum(sales_received)::numeric,2) FROM analytics.mv_store_theoretical_actual_cost_monthly WHERE month_start = '${MONTH_START}' UNION ALL SELECT 'op_expense', count(*), round(sum(received)::numeric,2) FROM analytics.mv_store_operating_expense_monthly WHERE report_month = '${MONTH_START}'; SELECT '=== 门店覆盖检查 ===' AS header; SELECT r.store_code, r.store_name, r.received, CASE WHEN e.sales_store_code IS NOT NULL THEN '有费用' ELSE '无费用' END AS expense_status FROM analytics.mv_store_risk_rating_monthly r LEFT JOIN analytics.mv_store_operating_expense_monthly e ON r.store_code = e.sales_store_code AND e.report_month = '${MONTH_START}' WHERE r.month_start = '${MONTH_START}' AND r.received > 0 AND e.sales_store_code IS NULL ORDER BY r.received DESC; EOF echo "==========================================" echo " 刷新完成!" echo "=========================================="