-- ============================================================================ -- Evaluation Points Tenant Cleanup Precheck -- 目标: -- 1. 在执行 schema_evaluation_points_tenant_cleanup.sql 前先识别风险 -- 2. 输出 area 分布、无法映射记录、共享域残留、编码重复情况 -- 3. 供 DBA / 开发在评审和落库前人工确认 -- 说明: -- - 本脚本只读,不修改任何数据 -- - 建议在生产、预发、测试库分别执行并保存结果 -- ============================================================================ -- -------------------------------------------------------------------------- -- 0. 当前表结构确认 -- -------------------------------------------------------------------------- SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'evaluation_points' ORDER BY ordinal_position; -- -------------------------------------------------------------------------- -- 1. 基础体量 -- -------------------------------------------------------------------------- SELECT COUNT(*) AS total_points FROM public.evaluation_points; -- -------------------------------------------------------------------------- -- 1.1 构建兼容旧库的预检视图 -- - 若旧库还没有 tenant_code / tenant_name,则自动补 NULL 占位 -- - 后续所有预检统一只读这个临时视图 -- -------------------------------------------------------------------------- DO $$ DECLARE has_tenant_code BOOLEAN; has_tenant_name BOOLEAN; tenant_code_expr TEXT; tenant_name_expr TEXT; BEGIN SELECT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'evaluation_points' AND column_name = 'tenant_code' ) INTO has_tenant_code; SELECT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'evaluation_points' AND column_name = 'tenant_name' ) INTO has_tenant_name; tenant_code_expr := CASE WHEN has_tenant_code THEN 'tenant_code' ELSE 'NULL::VARCHAR(64) AS tenant_code' END; tenant_name_expr := CASE WHEN has_tenant_name THEN 'tenant_name' ELSE 'NULL::VARCHAR(128) AS tenant_name' END; EXECUTE format( 'CREATE TEMP VIEW tmp_evaluation_points_precheck AS SELECT id, code, name, area, %s, %s FROM public.evaluation_points', tenant_code_expr, tenant_name_expr ); END $$; SELECT COUNT(*) AS total_points, COUNT(*) FILTER (WHERE tenant_code IS NULL OR BTRIM(tenant_code) = '') AS missing_tenant_code, COUNT(*) FILTER (WHERE tenant_name IS NULL OR BTRIM(tenant_name) = '') AS missing_tenant_name, COUNT(*) FILTER (WHERE area IS NULL OR BTRIM(area) = '') AS blank_area FROM tmp_evaluation_points_precheck; -- -------------------------------------------------------------------------- -- 2. area 值分布 -- -------------------------------------------------------------------------- SELECT COALESCE(NULLIF(BTRIM(area), ''), '') AS area_value, COUNT(*) AS point_count FROM tmp_evaluation_points_precheck GROUP BY 1 ORDER BY point_count DESC, area_value ASC; -- -------------------------------------------------------------------------- -- 3. area 无法映射租户编码的残留清单 -- 规则:别名表 -> 租户名 -> 共享域兼容值 -- -------------------------------------------------------------------------- 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_points AS ( SELECT ep.id, ep.code, ep.name, ep.area, COALESCE( NULLIF(BTRIM(ep.tenant_code), ''), am.tenant_code, tn.tenant_code, CASE WHEN ep.area IS NULL OR BTRIM(ep.area) = '' THEN 'PUBLIC' WHEN LOWER(BTRIM(ep.area)) = 'default' THEN 'PUBLIC' WHEN BTRIM(ep.area) = '公共' THEN 'PUBLIC' WHEN BTRIM(ep.area) IN ('省级', '省局') THEN 'PROVINCIAL' ELSE NULL END ) AS resolved_tenant_code FROM tmp_evaluation_points_precheck ep LEFT JOIN alias_map am ON LOWER(BTRIM(COALESCE(ep.area, ''))) = am.normalized_alias_value LEFT JOIN tenant_name_map tn ON LOWER(BTRIM(COALESCE(ep.area, ''))) = tn.normalized_tenant_name ) SELECT id, code, name, area FROM resolved_points WHERE resolved_tenant_code IS NULL ORDER BY id ASC; -- -------------------------------------------------------------------------- -- 4. 共享域残留统计 -- -------------------------------------------------------------------------- SELECT CASE WHEN area IS NULL OR BTRIM(area) = '' THEN '' ELSE BTRIM(area) END AS shared_area_value, COUNT(*) AS point_count FROM tmp_evaluation_points_precheck WHERE area IS NULL OR BTRIM(area) = '' OR LOWER(BTRIM(area)) = 'default' OR BTRIM(area) IN ('公共', '省级', '省局') GROUP BY 1 ORDER BY point_count DESC, shared_area_value ASC; -- -------------------------------------------------------------------------- -- 5. tenant_name 映射冲突预检 -- -------------------------------------------------------------------------- SELECT LOWER(BTRIM(tenant_name)) AS normalized_tenant_name, COUNT(DISTINCT tenant_code) AS tenant_code_count, ARRAY_AGG(DISTINCT tenant_code ORDER BY tenant_code) AS tenant_codes FROM public.sys_tenants WHERE deleted_at IS NULL AND is_enabled = TRUE AND tenant_name IS NOT NULL AND BTRIM(tenant_name) <> '' GROUP BY 1 HAVING COUNT(DISTINCT tenant_code) > 1 ORDER BY normalized_tenant_name ASC; -- -------------------------------------------------------------------------- -- 6. alias 映射冲突预检 -- -------------------------------------------------------------------------- SELECT LOWER(BTRIM(alias_value)) AS normalized_alias_value, COUNT(DISTINCT tenant_code) AS tenant_code_count, ARRAY_AGG(DISTINCT tenant_code ORDER BY tenant_code) AS tenant_codes FROM public.sys_tenant_aliases WHERE deleted_at IS NULL AND is_enabled = TRUE AND alias_value IS NOT NULL AND BTRIM(alias_value) <> '' GROUP BY 1 HAVING COUNT(DISTINCT tenant_code) > 1 ORDER BY normalized_alias_value ASC; -- -------------------------------------------------------------------------- -- 7. 编码唯一性现状预检 -- 注意:当前 service 仍按全局唯一校验 code,不是按 tenant_code + code 校验 -- -------------------------------------------------------------------------- SELECT LOWER(BTRIM(code)) AS normalized_code, COUNT(*) AS duplicate_count, ARRAY_AGG(id ORDER BY id) AS point_ids FROM tmp_evaluation_points_precheck WHERE code IS NOT NULL AND BTRIM(code) <> '' GROUP BY 1 HAVING COUNT(*) > 1 ORDER BY duplicate_count DESC, normalized_code ASC; -- -------------------------------------------------------------------------- -- 8. 若后续想把 code 改成“按租户唯一”,先看跨租户重复情况 -- 这里用“预估 tenant_code”做模拟,不代表当前表已有 tenant_code -- -------------------------------------------------------------------------- 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_points AS ( SELECT ep.id, LOWER(BTRIM(ep.code)) AS normalized_code, COALESCE( NULLIF(BTRIM(ep.tenant_code), ''), am.tenant_code, tn.tenant_code, CASE WHEN ep.area IS NULL OR BTRIM(ep.area) = '' THEN 'PUBLIC' WHEN LOWER(BTRIM(ep.area)) = 'default' THEN 'PUBLIC' WHEN BTRIM(ep.area) = '公共' THEN 'PUBLIC' WHEN BTRIM(ep.area) IN ('省级', '省局') THEN 'PROVINCIAL' ELSE NULL END ) AS resolved_tenant_code FROM tmp_evaluation_points_precheck ep LEFT JOIN alias_map am ON LOWER(BTRIM(COALESCE(ep.area, ''))) = am.normalized_alias_value LEFT JOIN tenant_name_map tn ON LOWER(BTRIM(COALESCE(ep.area, ''))) = tn.normalized_tenant_name WHERE ep.code IS NOT NULL AND BTRIM(ep.code) <> '' ) SELECT normalized_code, COUNT(*) AS duplicate_count, COUNT(DISTINCT resolved_tenant_code) AS tenant_count, ARRAY_AGG( CONCAT(id, ':', COALESCE(resolved_tenant_code, '')) ORDER BY id ) AS point_ids_with_tenant FROM resolved_points GROUP BY normalized_code HAVING COUNT(*) > 1 ORDER BY duplicate_count DESC, normalized_code ASC; -- -------------------------------------------------------------------------- -- 9. 执行后验收时建议对照的基线统计 -- -------------------------------------------------------------------------- SELECT COUNT(*) FILTER (WHERE tenant_code IS NULL OR BTRIM(tenant_code) = '') AS missing_tenant_code, COUNT(*) FILTER (WHERE tenant_name IS NULL OR BTRIM(tenant_name) = '') AS missing_tenant_name FROM tmp_evaluation_points_precheck;