BEGIN; -- ============================================================================ -- High Risk Tenant Code Phase 1 -- 目标: -- 1. 为高风险核心业务表补 tenant_code / tenant 快照字段 -- 2. 补基础索引,支持后续 service 改为 tenant_code 主链 -- 3. 基于 sys_tenant_aliases / sys_tenants 做第一轮历史回填 -- 说明: -- - 本脚本只做“补列 + 建索引 + 回填” -- - 不在本阶段强制 NOT NULL -- - 不在本阶段删除旧 region/area 字段 -- ============================================================================ -- -------------------------------------------------------------------------- -- 1. leaudit_documents -- -------------------------------------------------------------------------- ALTER TABLE public.leaudit_documents ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64); COMMENT ON COLUMN public.leaudit_documents.tenant_code IS '所属租户编码:高风险阶段新增,后续替代 region 作为真实归属主字段'; CREATE INDEX IF NOT EXISTS idx_leaudit_documents_tenant_code ON public.leaudit_documents(tenant_code) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS idx_leaudit_documents_type_tenant_name_latest ON public.leaudit_documents(type_id, tenant_code, normalized_name, is_latest_version) WHERE deleted_at IS NULL; -- -------------------------------------------------------------------------- -- 2. contract_templates -- -------------------------------------------------------------------------- ALTER TABLE public.contract_templates ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64), ADD COLUMN IF NOT EXISTS tenant_name VARCHAR(128); COMMENT ON COLUMN public.contract_templates.tenant_code IS '所属租户编码:高风险阶段新增,后续替代 region 作为真实归属主字段'; COMMENT ON COLUMN public.contract_templates.tenant_name IS '所属租户名称:展示字段,和 tenant_code 配套回填'; CREATE INDEX IF NOT EXISTS idx_contract_templates_tenant_code_active ON public.contract_templates(tenant_code) WHERE deleted_at IS NULL; CREATE UNIQUE INDEX IF NOT EXISTS uq_contract_templates_tenant_code_code_active ON public.contract_templates(tenant_code, template_code) WHERE deleted_at IS NULL; -- -------------------------------------------------------------------------- -- 3. usage_login_events -- -------------------------------------------------------------------------- ALTER TABLE public.usage_login_events ADD COLUMN IF NOT EXISTS tenant_code_snapshot VARCHAR(64), ADD COLUMN IF NOT EXISTS tenant_name_snapshot VARCHAR(128); COMMENT ON COLUMN public.usage_login_events.tenant_code_snapshot IS '登录时租户编码快照'; COMMENT ON COLUMN public.usage_login_events.tenant_name_snapshot IS '登录时租户名称快照'; CREATE INDEX IF NOT EXISTS idx_usage_login_events_tenant_code ON public.usage_login_events(tenant_code_snapshot, login_time DESC); -- -------------------------------------------------------------------------- -- 4. rag_dataset -- -------------------------------------------------------------------------- ALTER TABLE public.rag_dataset ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64); COMMENT ON COLUMN public.rag_dataset.tenant_code IS '所属租户编码:高风险阶段新增,后续替代 area 作为真实归属主字段'; CREATE INDEX IF NOT EXISTS idx_rag_dataset_tenant_code ON public.rag_dataset(tenant_code) WHERE deleted_at IS NULL; -- -------------------------------------------------------------------------- -- 5. rag_chat_app -- -------------------------------------------------------------------------- ALTER TABLE public.rag_chat_app ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64); COMMENT ON COLUMN public.rag_chat_app.tenant_code IS '所属租户编码:高风险阶段新增,后续替代 area 作为真实归属主字段'; CREATE INDEX IF NOT EXISTS idx_rag_chat_app_tenant_code ON public.rag_chat_app(tenant_code) WHERE deleted_at IS NULL; -- -------------------------------------------------------------------------- -- 6. 公共 / 省级规范租户兜底 -- -------------------------------------------------------------------------- INSERT INTO public.sys_tenants ( tenant_code, tenant_name, tenant_short_name, tenant_type, parent_tenant_code, is_enabled, is_public, display_order, ext, created_at, updated_at, deleted_at ) SELECT 'PUBLIC', '公共资源域', '公共', 'PUBLIC', NULL, TRUE, TRUE, 0, '{}'::jsonb, NOW(), NOW(), NULL WHERE NOT EXISTS ( SELECT 1 FROM public.sys_tenants WHERE tenant_code = 'PUBLIC' ); INSERT INTO public.sys_tenants ( tenant_code, tenant_name, tenant_short_name, tenant_type, parent_tenant_code, is_enabled, is_public, display_order, ext, created_at, updated_at, deleted_at ) SELECT 'PROVINCIAL', '省级统管域', '省级', 'GOV', NULL, TRUE, FALSE, 1, '{}'::jsonb, NOW(), NOW(), NULL WHERE NOT EXISTS ( SELECT 1 FROM public.sys_tenants WHERE tenant_code = 'PROVINCIAL' ); INSERT INTO public.sys_tenant_aliases ( tenant_code, alias_type, alias_value, is_enabled, created_at, updated_at, deleted_at ) SELECT 'PUBLIC', 'DISPLAY', '公共', TRUE, NOW(), NOW(), NULL WHERE NOT EXISTS ( SELECT 1 FROM public.sys_tenant_aliases WHERE tenant_code = 'PUBLIC' AND alias_value = '公共' AND deleted_at IS NULL ); INSERT INTO public.sys_tenant_aliases ( tenant_code, alias_type, alias_value, is_enabled, created_at, updated_at, deleted_at ) SELECT 'PUBLIC', 'LEGACY_REGION', 'default', TRUE, NOW(), NOW(), NULL WHERE NOT EXISTS ( SELECT 1 FROM public.sys_tenant_aliases WHERE tenant_code = 'PUBLIC' AND alias_value = 'default' AND deleted_at IS NULL ); INSERT INTO public.sys_tenant_aliases ( tenant_code, alias_type, alias_value, is_enabled, created_at, updated_at, deleted_at ) SELECT 'PROVINCIAL', 'DISPLAY', '省级', TRUE, NOW(), NOW(), NULL WHERE NOT EXISTS ( SELECT 1 FROM public.sys_tenant_aliases WHERE tenant_code = 'PROVINCIAL' AND alias_value = '省级' AND deleted_at IS NULL ); INSERT INTO public.sys_tenant_aliases ( tenant_code, alias_type, alias_value, is_enabled, created_at, updated_at, deleted_at ) SELECT 'PROVINCIAL', 'LEGACY_REGION', '省局', TRUE, NOW(), NOW(), NULL WHERE NOT EXISTS ( SELECT 1 FROM public.sys_tenant_aliases WHERE tenant_code = 'PROVINCIAL' AND alias_value = '省局' AND deleted_at IS NULL ); -- -------------------------------------------------------------------------- -- 7. 第一轮历史回填:优先按别名表映射 -- -------------------------------------------------------------------------- WITH alias_map AS ( SELECT DISTINCT ON (LOWER(BTRIM(alias_value))) LOWER(BTRIM(alias_value)) AS normalized_alias_value, tenant_code FROM public.sys_tenant_aliases WHERE deleted_at IS NULL AND is_enabled = TRUE ORDER BY LOWER(BTRIM(alias_value)), id ASC ), tenant_name_map AS ( SELECT LOWER(BTRIM(tenant_name)) AS normalized_tenant_name, tenant_code FROM public.sys_tenants WHERE deleted_at IS NULL AND is_enabled = TRUE ), resolved_documents AS ( SELECT d.id, COALESCE( NULLIF(BTRIM(d.tenant_code), ''), am.tenant_code, tn.tenant_code, CASE WHEN d.region IS NULL OR BTRIM(d.region) = '' THEN 'PUBLIC' WHEN LOWER(BTRIM(d.region)) = 'default' THEN 'PUBLIC' WHEN BTRIM(d.region) = '公共' THEN 'PUBLIC' WHEN BTRIM(d.region) IN ('省级', '省局') THEN 'PROVINCIAL' ELSE NULL END ) AS resolved_tenant_code FROM public.leaudit_documents d LEFT JOIN alias_map am ON LOWER(BTRIM(COALESCE(d.region, ''))) = am.normalized_alias_value LEFT JOIN tenant_name_map tn ON LOWER(BTRIM(COALESCE(d.region, ''))) = tn.normalized_tenant_name WHERE d.deleted_at IS NULL AND (d.tenant_code IS NULL OR BTRIM(d.tenant_code) = '') ) UPDATE public.leaudit_documents d SET tenant_code = rd.resolved_tenant_code FROM resolved_documents rd WHERE d.id = rd.id AND rd.resolved_tenant_code IS NOT NULL; WITH alias_map AS ( SELECT DISTINCT ON (LOWER(BTRIM(alias_value))) LOWER(BTRIM(alias_value)) AS normalized_alias_value, tenant_code FROM public.sys_tenant_aliases WHERE deleted_at IS NULL AND is_enabled = TRUE ORDER BY LOWER(BTRIM(alias_value)), id ASC ), tenant_name_map AS ( SELECT LOWER(BTRIM(tenant_name)) AS normalized_tenant_name, tenant_code FROM public.sys_tenants WHERE deleted_at IS NULL AND is_enabled = TRUE ), resolved_templates AS ( SELECT t.id, COALESCE( NULLIF(BTRIM(t.tenant_code), ''), am.tenant_code, tn.tenant_code, CASE WHEN t.region IS NULL OR BTRIM(t.region) = '' THEN 'PROVINCIAL' WHEN LOWER(BTRIM(t.region)) = 'default' THEN 'PUBLIC' WHEN BTRIM(t.region) = '公共' THEN 'PUBLIC' WHEN BTRIM(t.region) IN ('省级', '省局') THEN 'PROVINCIAL' ELSE NULL END ) AS resolved_tenant_code, COALESCE( NULLIF(BTRIM(t.tenant_name), ''), NULLIF(BTRIM(t.region), ''), st.tenant_name, CASE WHEN t.region IS NULL OR BTRIM(t.region) = '' THEN '省级' WHEN LOWER(BTRIM(t.region)) = 'default' THEN '公共' WHEN BTRIM(t.region) = '公共' THEN '公共' WHEN BTRIM(t.region) IN ('省级', '省局') THEN '省级' ELSE NULL END ) AS resolved_tenant_name FROM public.contract_templates t LEFT JOIN alias_map am ON LOWER(BTRIM(COALESCE(t.region, ''))) = am.normalized_alias_value LEFT JOIN tenant_name_map tn ON LOWER(BTRIM(COALESCE(t.region, ''))) = tn.normalized_tenant_name LEFT JOIN public.sys_tenants st ON st.tenant_code = COALESCE( NULLIF(BTRIM(t.tenant_code), ''), am.tenant_code, tn.tenant_code, CASE WHEN t.region IS NULL OR BTRIM(t.region) = '' THEN 'PROVINCIAL' WHEN LOWER(BTRIM(t.region)) = 'default' THEN 'PUBLIC' WHEN BTRIM(t.region) = '公共' THEN 'PUBLIC' WHEN BTRIM(t.region) IN ('省级', '省局') THEN 'PROVINCIAL' ELSE NULL END ) AND st.deleted_at IS NULL AND st.is_enabled = TRUE WHERE t.deleted_at IS NULL AND ( t.tenant_code IS NULL OR BTRIM(t.tenant_code) = '' OR t.tenant_name IS NULL OR BTRIM(t.tenant_name) = '' ) ) UPDATE public.contract_templates t SET tenant_code = COALESCE(t.tenant_code, rt.resolved_tenant_code), tenant_name = COALESCE(NULLIF(BTRIM(t.tenant_name), ''), rt.resolved_tenant_name) FROM resolved_templates rt WHERE t.id = rt.id AND ( rt.resolved_tenant_code IS NOT NULL OR rt.resolved_tenant_name IS NOT NULL ); WITH alias_map AS ( SELECT DISTINCT ON (LOWER(BTRIM(alias_value))) LOWER(BTRIM(alias_value)) AS normalized_alias_value, tenant_code FROM public.sys_tenant_aliases WHERE deleted_at IS NULL AND is_enabled = TRUE ORDER BY LOWER(BTRIM(alias_value)), id ASC ), tenant_name_map AS ( SELECT LOWER(BTRIM(tenant_name)) AS normalized_tenant_name, tenant_code FROM public.sys_tenants WHERE deleted_at IS NULL AND is_enabled = TRUE ), resolved_rag_dataset AS ( SELECT d.id, COALESCE( NULLIF(BTRIM(d.tenant_code), ''), am.tenant_code, tn.tenant_code, CASE WHEN d.area IS NULL OR BTRIM(d.area) = '' THEN 'PUBLIC' WHEN LOWER(BTRIM(d.area)) = 'default' THEN 'PUBLIC' WHEN BTRIM(d.area) = '公共' THEN 'PUBLIC' WHEN BTRIM(d.area) IN ('省级', '省局') THEN 'PROVINCIAL' ELSE NULL END ) AS resolved_tenant_code FROM public.rag_dataset d LEFT JOIN alias_map am ON LOWER(BTRIM(COALESCE(d.area, ''))) = am.normalized_alias_value LEFT JOIN tenant_name_map tn ON LOWER(BTRIM(COALESCE(d.area, ''))) = tn.normalized_tenant_name WHERE d.deleted_at IS NULL AND (d.tenant_code IS NULL OR BTRIM(d.tenant_code) = '') ) UPDATE public.rag_dataset d SET tenant_code = rrd.resolved_tenant_code FROM resolved_rag_dataset rrd WHERE d.id = rrd.id AND rrd.resolved_tenant_code IS NOT NULL; WITH alias_map AS ( SELECT DISTINCT ON (LOWER(BTRIM(alias_value))) LOWER(BTRIM(alias_value)) AS normalized_alias_value, tenant_code FROM public.sys_tenant_aliases WHERE deleted_at IS NULL AND is_enabled = TRUE ORDER BY LOWER(BTRIM(alias_value)), id ASC ), tenant_name_map AS ( SELECT LOWER(BTRIM(tenant_name)) AS normalized_tenant_name, tenant_code FROM public.sys_tenants WHERE deleted_at IS NULL AND is_enabled = TRUE ), resolved_rag_chat_app AS ( SELECT a.id, COALESCE( NULLIF(BTRIM(a.tenant_code), ''), am.tenant_code, tn.tenant_code, CASE WHEN a.area IS NULL OR BTRIM(a.area) = '' THEN 'PUBLIC' WHEN LOWER(BTRIM(a.area)) = 'default' THEN 'PUBLIC' WHEN BTRIM(a.area) = '公共' THEN 'PUBLIC' WHEN BTRIM(a.area) IN ('省级', '省局') THEN 'PROVINCIAL' ELSE NULL END ) AS resolved_tenant_code FROM public.rag_chat_app a LEFT JOIN alias_map am ON LOWER(BTRIM(COALESCE(a.area, ''))) = am.normalized_alias_value LEFT JOIN tenant_name_map tn ON LOWER(BTRIM(COALESCE(a.area, ''))) = tn.normalized_tenant_name WHERE a.deleted_at IS NULL AND (a.tenant_code IS NULL OR BTRIM(a.tenant_code) = '') ) UPDATE public.rag_chat_app a SET tenant_code = rca.resolved_tenant_code FROM resolved_rag_chat_app rca WHERE a.id = rca.id AND rca.resolved_tenant_code IS NOT NULL; WITH user_tenant_map AS ( SELECT u.id AS user_id, COALESCE( NULLIF(BTRIM(u.tenant_code), ''), am.tenant_code, tn.tenant_code, CASE WHEN u.area IS NULL OR BTRIM(u.area) = '' THEN 'PUBLIC' WHEN LOWER(BTRIM(u.area)) = 'default' THEN 'PUBLIC' WHEN BTRIM(u.area) = '公共' THEN 'PUBLIC' WHEN BTRIM(u.area) IN ('省级', '省局') THEN 'PROVINCIAL' ELSE NULL END ) AS resolved_tenant_code, COALESCE( NULLIF(BTRIM(u.tenant_name), ''), t.tenant_name, NULLIF(BTRIM(u.area), ''), CASE WHEN u.area IS NULL OR BTRIM(u.area) = '' THEN '公共资源域' ELSE NULL END ) AS resolved_tenant_name FROM public.sso_users u LEFT JOIN public.sys_tenant_aliases sa ON LOWER(BTRIM(COALESCE(u.area, ''))) = LOWER(BTRIM(sa.alias_value)) AND sa.deleted_at IS NULL AND sa.is_enabled = TRUE LEFT JOIN public.sys_tenants t ON t.tenant_code = COALESCE(NULLIF(BTRIM(u.tenant_code), ''), sa.tenant_code) AND t.deleted_at IS NULL AND t.is_enabled = TRUE LEFT JOIN ( SELECT DISTINCT ON (LOWER(BTRIM(alias_value))) LOWER(BTRIM(alias_value)) AS normalized_alias_value, tenant_code FROM public.sys_tenant_aliases WHERE deleted_at IS NULL AND is_enabled = TRUE ORDER BY LOWER(BTRIM(alias_value)), id ASC ) am ON LOWER(BTRIM(COALESCE(u.area, ''))) = am.normalized_alias_value LEFT JOIN ( SELECT LOWER(BTRIM(tenant_name)) AS normalized_tenant_name, tenant_code FROM public.sys_tenants WHERE deleted_at IS NULL AND is_enabled = TRUE ) tn ON LOWER(BTRIM(COALESCE(u.area, ''))) = tn.normalized_tenant_name WHERE u.deleted_at IS NULL ) UPDATE public.usage_login_events e SET tenant_code_snapshot = COALESCE(e.tenant_code_snapshot, utm.resolved_tenant_code), tenant_name_snapshot = COALESCE(e.tenant_name_snapshot, utm.resolved_tenant_name) FROM user_tenant_map utm WHERE e.deleted_at IS NULL AND e.user_id = utm.user_id AND ( e.tenant_code_snapshot IS NULL OR BTRIM(e.tenant_code_snapshot) = '' OR e.tenant_name_snapshot IS NULL OR BTRIM(e.tenant_name_snapshot) = '' ); COMMIT;