-- 1.0.296.sql  S0 Warehouse P1：ItemPackMaster / NbrControl 唯一索引租户化（幂等 + 冲突前置守卫）。
--   目的：唯一约束从「全局业务键」改为「租户内业务键」，使不同租户可复用相同业务编码，
--         同一租户内重复业务键仍被数据库拒绝。
--   不改字段类型、不改 tenant_id 可空性、不插入/更新/删除任何业务数据、不动其它表索引。
--   业务键依据（information_schema 实证 + 消费链路审计）：
--     ItemPackMaster：历史唯一键 (Domain, ItemNum)；Domain 与 factory_ref_id 在数据中 1:1；
--                     tenant 内唯一键 = (tenant_id, Domain, ItemNum)。
--     NbrControl    ：历史唯一键 (domain_code, NbrType)；domain_code NOT NULL（现值全为空串，作安全唯一锚），
--                     NbrType 为真实单号类型码；tenant 内唯一键 = (tenant_id, domain_code, NbrType)。
-- ============================================================================

-- ========== 一、冲突前置检测（同租户内重复则跳过创建，绝不自动清理历史数据） ==========
SET @ipk_dup := (SELECT COUNT(*) FROM (
    SELECT tenant_id, `Domain`, ItemNum
    FROM ItemPackMaster
    GROUP BY tenant_id, `Domain`, ItemNum
    HAVING COUNT(*) > 1) t);

SET @nbr_dup := (SELECT COUNT(*) FROM (
    SELECT tenant_id, domain_code, NbrType
    FROM NbrControl
    GROUP BY tenant_id, domain_code, NbrType
    HAVING COUNT(*) > 1) t);

SELECT @ipk_dup AS itempack_intratenant_dup, @nbr_dup AS nbrcontrol_intratenant_dup;
-- 期望均为 0；若非 0，本脚本不会创建新唯一索引（下方 ADD 被守卫跳过），需人工治理后重跑。

-- ========== 二、ItemPackMaster：旧全局唯一索引 -> 租户内唯一索引 ==========
-- 2.1 删除旧唯一索引 uk_ItemPackMaster_domain_itemnum（存在才删）
SET @has_old_ipk := (SELECT COUNT(DISTINCT INDEX_NAME) FROM information_schema.STATISTICS
    WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ItemPackMaster'
      AND INDEX_NAME = 'uk_ItemPackMaster_domain_itemnum');
SET @sql := IF(@has_old_ipk > 0,
    'ALTER TABLE ItemPackMaster DROP INDEX uk_ItemPackMaster_domain_itemnum', 'DO 0');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;

-- 2.2 创建新租户内唯一索引（不存在且无同租户冲突才建）
SET @has_new_ipk := (SELECT COUNT(DISTINCT INDEX_NAME) FROM information_schema.STATISTICS
    WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ItemPackMaster'
      AND INDEX_NAME = 'uk_ItemPackMaster_tenant_domain_itemnum');
SET @sql := IF(@has_new_ipk = 0 AND @ipk_dup = 0,
    'ALTER TABLE ItemPackMaster ADD UNIQUE INDEX uk_ItemPackMaster_tenant_domain_itemnum (tenant_id, `Domain`, ItemNum)',
    'DO 0');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;

-- 2.3 处理隐藏的第二个全局唯一索引 ix_ItemPackMaster (Domain, ItemNum)。
--     该索引 NON_UNIQUE=0（唯一），与被删的 uk 同样强制全局唯一，会继续阻断跨租户相同 (Domain, ItemNum)，必须一并处理。
--     方案：删除其“唯一”版本，重建为“非唯一”同名索引（保留 (Domain, ItemNum) 查询性能，但不再强制全局唯一）。
SET @ix_unique := (SELECT COUNT(*) FROM information_schema.STATISTICS
    WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ItemPackMaster'
      AND INDEX_NAME = 'ix_ItemPackMaster' AND NON_UNIQUE = 0);
SET @sql := IF(@ix_unique > 0,
    'ALTER TABLE ItemPackMaster DROP INDEX ix_ItemPackMaster', 'DO 0');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;

SET @has_ix := (SELECT COUNT(DISTINCT INDEX_NAME) FROM information_schema.STATISTICS
    WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ItemPackMaster'
      AND INDEX_NAME = 'ix_ItemPackMaster');
SET @sql := IF(@has_ix = 0,
    'ALTER TABLE ItemPackMaster ADD INDEX ix_ItemPackMaster (`Domain`, ItemNum)', 'DO 0');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;

-- ========== 三、NbrControl：旧全局唯一索引 -> 租户内唯一索引 ==========
-- 3.1 删除旧唯一索引 uk_NbrControl_domain_nbrtype（存在才删）
SET @has_old_nbr := (SELECT COUNT(DISTINCT INDEX_NAME) FROM information_schema.STATISTICS
    WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'NbrControl'
      AND INDEX_NAME = 'uk_NbrControl_domain_nbrtype');
SET @sql := IF(@has_old_nbr > 0,
    'ALTER TABLE NbrControl DROP INDEX uk_NbrControl_domain_nbrtype', 'DO 0');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;

-- 3.2 创建新租户内唯一索引（不存在且无同租户冲突才建）
SET @has_new_nbr := (SELECT COUNT(DISTINCT INDEX_NAME) FROM information_schema.STATISTICS
    WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'NbrControl'
      AND INDEX_NAME = 'uk_NbrControl_tenant_domain_nbrtype');
SET @sql := IF(@has_new_nbr = 0 AND @nbr_dup = 0,
    'ALTER TABLE NbrControl ADD UNIQUE INDEX uk_NbrControl_tenant_domain_nbrtype (tenant_id, domain_code, NbrType)',
    'DO 0');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;

-- ========== 四、执行后验证 ==========
SELECT TABLE_NAME, INDEX_NAME, NON_UNIQUE, SEQ_IN_INDEX, COLUMN_NAME
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
  AND TABLE_NAME IN ('ItemPackMaster', 'NbrControl')
  AND INDEX_NAME <> 'PRIMARY'
ORDER BY TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX;
-- 期望：ItemPackMaster 仅 uk_ItemPackMaster_tenant_domain_itemnum(唯一) + ix_ItemPackMaster(NON_UNIQUE=1)；
--       NbrControl 仅 uk_NbrControl_tenant_domain_nbrtype(唯一)。均无全局唯一 (Domain,ItemNum)/(domain_code,NbrType)。

-- ============================================================================
-- 回滚 SQL（如需恢复到全局唯一索引，历史数据无跨租户同键冲突时可执行）：
--   ALTER TABLE ItemPackMaster DROP INDEX uk_ItemPackMaster_tenant_domain_itemnum;
--   ALTER TABLE ItemPackMaster DROP INDEX ix_ItemPackMaster;
--   ALTER TABLE ItemPackMaster ADD UNIQUE INDEX uk_ItemPackMaster_domain_itemnum (`Domain`, ItemNum);
--   ALTER TABLE ItemPackMaster ADD UNIQUE INDEX ix_ItemPackMaster (`Domain`, ItemNum);
--   ALTER TABLE NbrControl     DROP INDEX uk_NbrControl_tenant_domain_nbrtype;
--   ALTER TABLE NbrControl     ADD UNIQUE INDEX uk_NbrControl_domain_nbrtype (domain_code, NbrType);
-- 注意：回滚前必须确认不存在跨租户相同业务键，否则回滚 ADD 会因重复而失败（这正是本次改造要放开的场景）。
-- ============================================================================
