Files
order_site/deploy/sql/prepare-113-finance-cutover.sql
T

151 lines
4.8 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- 113 迁移前置兼容修复。
--
-- 113 已经进入生产,文件必须保持字节不变。旧快照库中存在两类历史脏数据,
-- 会让原版 113 在“加新约束/唯一索引”时失败:
-- 1. sales_daily_facts 仍有旧约束不接受的渠道值;
-- 2. cost_exceptions 同一范围的旧行会生成重复 scope_key。
--
-- 本文件不是迁移,不写 schema_migrations。它只做幂等兼容准备:
-- - 113 已执行时立即跳过;
-- - 清理旧库数据,让随后执行的原版 113 可以通过。
--
-- 由 deploy/ubuntu-deploy.sh 在数据库迁移前自动执行。
DO $preflight$
DECLARE
v_has_113 BOOLEAN := FALSE;
v_sales_has_mode BOOLEAN := FALSE;
v_scope_duplicates BIGINT := 0;
v_scope_missing BIGINT := 0;
BEGIN
IF to_regclass('public.schema_migrations') IS NOT NULL THEN
EXECUTE $query$
SELECT EXISTS (
SELECT 1
FROM public.schema_migrations migration
WHERE to_jsonb(migration)->>'filename' = '113_finance_channel_cutover.sql'
OR to_jsonb(migration)->>'name' = '113_finance_channel_cutover'
)
$query$ INTO v_has_113;
END IF;
IF v_has_113 THEN
RAISE NOTICE '113 已执行,跳过前置兼容修复';
RETURN;
END IF;
IF to_regclass('public.sales_daily_facts') IS NOT NULL THEN
SELECT EXISTS (
SELECT 1
FROM pg_attribute
WHERE attrelid = 'public.sales_daily_facts'::regclass
AND attname = 'fulfillment_mode'
AND NOT attisdropped
) INTO v_sales_has_mode;
IF v_sales_has_mode THEN
EXECUTE $sql$
ALTER TABLE public.sales_daily_facts
DROP CONSTRAINT IF EXISTS chk_sales_daily_facts_fulfillment_mode
$sql$;
EXECUTE $sql$
UPDATE public.sales_daily_facts
SET fulfillment_mode = CASE
WHEN fulfillment_mode = 'legacy_platform' THEN 'archived'
ELSE 'unclassified'
END
WHERE fulfillment_mode NOT IN (
'work_order', 'affiliate_dash', 'third_party_voucher',
'manual', 'unclassified', 'archived'
)
$sql$;
-- 迁移前临时使用新旧并集的约束;原版 113 会立即替换成最终约束。
EXECUTE $sql$
ALTER TABLE public.sales_daily_facts
ADD CONSTRAINT chk_sales_daily_facts_fulfillment_mode
CHECK (
fulfillment_mode IN (
'work_order', 'affiliate_dash', 'third_party_voucher',
'manual', 'unclassified', 'archived'
)
)
$sql$;
RAISE NOTICE 'sales_daily_facts 历史渠道值已兼容归一';
END IF;
END IF;
IF to_regclass('public.cost_exceptions') IS NOT NULL THEN
EXECUTE $sql$
ALTER TABLE public.cost_exceptions
ADD COLUMN IF NOT EXISTS scope_key TEXT,
ADD COLUMN IF NOT EXISTS item_count INTEGER NOT NULL DEFAULT 1,
ADD COLUMN IF NOT EXISTS first_seen_at TIMESTAMPTZ,
ADD COLUMN IF NOT EXISTS last_seen_at TIMESTAMPTZ
$sql$;
EXECUTE $sql$
WITH duplicate_scope_keys AS (
SELECT scope_key
FROM public.cost_exceptions
WHERE status <> 'resolved'
AND NULLIF(BTRIM(scope_key), '') IS NOT NULL
GROUP BY scope_key
HAVING COUNT(*) > 1
)
UPDATE public.cost_exceptions ce
SET scope_key =
COALESCE(NULLIF(BTRIM(ce.reason), ''), 'legacy')
|| '|'
|| COALESCE(ce.order_item_id::text, ce.subject_id::text, ce.id::text)
|| '|legacy:'
|| ce.id,
first_seen_at = COALESCE(ce.first_seen_at, ce.created_at),
last_seen_at = COALESCE(ce.last_seen_at, ce.created_at)
WHERE ce.scope_key IS NULL
OR BTRIM(ce.scope_key) = ''
OR ce.first_seen_at IS NULL
OR ce.last_seen_at IS NULL
OR (
ce.status <> 'resolved'
AND ce.scope_key IN (SELECT scope_key FROM duplicate_scope_keys)
)
$sql$;
EXECUTE $sql$
SELECT COUNT(*)
FROM (
SELECT scope_key
FROM public.cost_exceptions
WHERE status <> 'resolved'
AND NULLIF(BTRIM(scope_key), '') IS NOT NULL
GROUP BY scope_key
HAVING COUNT(*) > 1
) duplicate_scope_keys
$sql$ INTO v_scope_duplicates;
EXECUTE $sql$
SELECT COUNT(*)
FROM public.cost_exceptions
WHERE scope_key IS NULL OR BTRIM(scope_key) = ''
$sql$ INTO v_scope_missing;
IF v_scope_duplicates > 0 THEN
RAISE EXCEPTION
'cost_exceptions 仍有 % 组重复 scope_key,113 无法创建唯一索引',
v_scope_duplicates;
END IF;
IF v_scope_missing > 0 THEN
RAISE EXCEPTION
'cost_exceptions 仍有 % 行 scope_key 为空,113 的唯一索引前置数据不完整',
v_scope_missing;
END IF;
RAISE NOTICE 'cost_exceptions 历史 scope_key 已保证唯一';
END IF;
END
$preflight$;