Files
leaudit-platform-backend/scripts/创建sql/precheck_evaluation_points_tenant_cleanup.sql
T

283 lines
9.8 KiB
SQL

-- ============================================================================
-- 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), ''), '<EMPTY>') 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 '<EMPTY>'
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, '<UNRESOLVED>'))
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;