Files
backend_v2/db/migrations/2026-10-16-01-brands-renumber-imported-ids.sql
toom1996 1de1ec46a6 update
2026-10-18 17:42:10 +08:00

63 lines
2.9 KiB
SQL
Raw Permalink 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.

-- 2026-10-16-01-brands-renumber-imported-ids.sql
--
-- 背景:2026-10-16 从 app_brands(MySQL dump)导入的 23218 个品牌带的是**源系统的显式 id**
-- (3097..26472)。而 brands.id 本身是 IDENTITY 列(GENERATED ... AS IDENTITY,序列
-- brands_id_seq),导入后序列仍停在 30 —— 新增品牌会从 31 开始编号,一旦涨到 3097
-- 就会与这批导入行**撞主键**。本迁移把那批行重排进真正的自增空间,并把序列对齐过去。
--
-- 安全性(迁移前已核对):全库没有任何行引用这些 id ——
-- * brand_runways.brand_id 最大只有 7(115 场走秀全部落在 19 个种子品牌内);
-- * favorites / histories 存的是内容(走秀/街拍)快照,不存品牌 id。
-- 19 个种子品牌(id ≤ 19)完全不动。
--
-- 三步:① 整批挪到负区间(避开主键中途相撞)② 按原 id 升序落回 20 起的连续区间
-- ③ 把 IDENTITY 序列对齐到新的最大值(下一次 nextval 即 max+1)。
--
-- ⚠️ 第 ② 步的 JOIN 必须用「当前的负数 id 本身」去匹配,**不能**拿子查询里的 -id(正数)
-- 去比 b.id(负数)—— 那样一行都匹配不上,会留下满表负数 id 的半途状态(本文件初版就踩了)。
--
-- 幂等:仅当「种子(≤19) 与导入批次(≥3097) 之间存在空洞(20..3096 全空)」时才重排;
-- 重排后 20..3096 已被占满,手动重跑会直接跳过。dbtool migrate 另按 schema_migrations 记账。
DO $$
DECLARE
v_before_max integer;
v_moved integer;
v_after_max integer;
BEGIN
IF EXISTS (SELECT 1 FROM brands WHERE id BETWEEN 20 AND 3096) THEN
RAISE NOTICE '[brands-renumber] 20..3096 非空,说明已重排过,跳过';
RETURN;
END IF;
-- 待处理的行:原始状态的 id >= 3097,或上一次中断留下的负数行。
IF NOT EXISTS (SELECT 1 FROM brands WHERE id < 0 OR id >= 3097) THEN
RAISE NOTICE '[brands-renumber] 没有待重排的行,跳过';
RETURN;
END IF;
SELECT max(id) INTO v_before_max FROM brands;
-- 1) 原始状态:整批挪到负区间(若已是负数则天然不匹配,空跑)。
UPDATE brands SET id = -id WHERE id >= 3097;
GET DIAGNOSTICS v_moved = ROW_COUNT;
-- 2) 按原 id 升序落回「紧接 19 个种子之后」的连续区间(排序固定,结果可复现)。
UPDATE brands b
SET id = m.new_id
FROM (
SELECT id AS neg_id,
(row_number() OVER (ORDER BY -id))::integer + 19 AS new_id
FROM brands
WHERE id < 0
) m
WHERE b.id = m.neg_id;
-- 3) 把 IDENTITY 序列对齐到新的最大值。
SELECT max(id) INTO v_after_max FROM brands;
PERFORM setval(pg_get_serial_sequence('brands', 'id'), v_after_max);
RAISE NOTICE '[brands-renumber] 完成:负区间挪动 % 行,id 最大值 % -> %,序列下次给出 %',
v_moved, v_before_max, v_after_max, v_after_max + 1;
END $$;