xiaoyi
2026-10-29 0641dcf9634a2b421a17eb166c9f153ae1f3c3f3
fix(safety): 修复 uk_code 唯一索引导致同编码二次软删除报 500

现象:巡检点位 PD-001 先软删一次,之后新建同编码 PD-001 再删除时,
接口返回「系统异常」(500),日志报
Duplicate entry 'PD-001-\x01' for key 'safety_inspection_point.uk_code'

原因:uk_code 建在 (code, deleted) 上,deleted 是 bit(1)。软删后 deleted=b'1',
若历史上已有一条同编码且已软删的记录,第二次软删除就会插入重复的
(code, b'1') 组合,撞唯一键。凡是有「编码 + 软删除」组合唯一键的表都会中招。

修复:去掉 (code, deleted) 唯一约束,改为普通索引 idx_code 用于查询;
编码唯一性由 Service 层保证(新增/修改时 selectByCode 只查活跃记录判重),
与 yudao 其它业务表一致(如 mes_dv_machinery 的 code 就没有唯一键)。

涉及 5 张表:safety_inspection_point / safety_hazard / safety_material /
safety_work_permit / safety_accident

验证:PD-TEST 建→删→再建→再删 连续 3 轮正常;
活跃记录同编码重复新建仍被拒绝(点位编码已存在)。

另外:.gitignore 忽略 .local-test/(本地验证用的生产库快照与覆盖配置)
已添加1个文件
已修改1个文件
61 ■■■■■ 文件已修改
.gitignore 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/mysql/safety_fix_code_index_20261029.sql 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -76,3 +76,10 @@
# æ•°æ®åº“变更脚本(手动执行,不入库)
sql/sale_order_bpm_approval.sql
.export_tmp/
# SSH MCP:依赖与本地配置(含凭据,绝不入库)
scripts/mcp-ssh/node_modules/
scripts/mcp-ssh/package-lock.json
# æœ¬åœ°éªŒè¯ç”¨ï¼šç”Ÿäº§åº“å¿«ç…§ + æœ¬åœ°è¦†ç›–配置,绝不入库
.local-test/
sql/mysql/safety_fix_code_index_20261029.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
-- ============================================================
-- å®‰å…¨ç”Ÿäº§ - ä¿®å¤ uk_code å”¯ä¸€ç´¢å¼•导致「第二次软删除同编码」报错
-- ç”Ÿæˆæ—¶é—´ï¼š2026-10-29
--
-- çŽ°è±¡ï¼šå·¡æ£€ç‚¹ä½ PD-001 å…ˆè¢«è½¯åˆ ä¸€æ¬¡ï¼Œä¹‹åŽæ–°å»ºåŒç¼–码 PD-001 å†åˆ é™¤æ—¶æŠ¥
--       Duplicate entry 'PD-001-\x01' for key 'safety_inspection_point.uk_code'
--       æŽ¥å£è¿”回「系统异常」(500)
--
-- åŽŸå› ï¼šuk_code å»ºåœ¨ (code, deleted) ä¸Šï¼Œdeleted æ˜¯ bit(1)。
--       è½¯åˆ é™¤åŽ deleted=b'1',若历史上已有一条同编码且已软删的记录,
--       ç¬¬äºŒæ¬¡è½¯åˆ é™¤å°±ä¼šæ’入重复的 (code, b'1') ç»„合,撞唯一键。
--
-- ä¿®å¤ï¼šåŽ»æŽ‰ (code, deleted) å”¯ä¸€çº¦æŸï¼Œæ”¹æˆæ™®é€šç´¢å¼• idx_code ç”¨äºŽæŸ¥è¯¢ï¼›
--       ç¼–码唯一性由 Service å±‚保证(新增/修改时 selectByCode æŸ¥æ´»è·ƒè®°å½•判重,
--       ä¸Ž yudao å…¶å®ƒä¸šåŠ¡è¡¨ä¸€è‡´ï¼Œä¾‹å¦‚ mes_dv_machinery å°±æ²¡æœ‰ code å”¯ä¸€é”®ï¼‰ã€‚
--
-- å¹‚等:先判断索引是否存在再操作,可重复执行
-- ============================================================
DROP PROCEDURE IF EXISTS sp_safety_fix_code_index;
DELIMITER $$
CREATE PROCEDURE sp_safety_fix_code_index(IN p_table VARCHAR(64))
BEGIN
  -- 1. åˆ æŽ‰æ—§çš„ (code, deleted) å”¯ä¸€é”®
  IF EXISTS (SELECT 1 FROM information_schema.statistics
              WHERE table_schema = DATABASE() AND table_name = p_table AND index_name = 'uk_code') THEN
    SET @s = CONCAT('ALTER TABLE `', p_table, '` DROP INDEX `uk_code`');
    PREPARE st FROM @s; EXECUTE st; DEALLOCATE PREPARE st;
  END IF;
  -- 2. è¡¥ä¸€ä¸ªæ™®é€šç´¢å¼•,保证按编码查询的性能
  IF NOT EXISTS (SELECT 1 FROM information_schema.statistics
                  WHERE table_schema = DATABASE() AND table_name = p_table AND index_name = 'idx_code') THEN
    SET @s2 = CONCAT('CREATE INDEX `idx_code` ON `', p_table, '` (`code`)');
    PREPARE st2 FROM @s2; EXECUTE st2; DEALLOCATE PREPARE st2;
  END IF;
END$$
DELIMITER ;
CALL sp_safety_fix_code_index('safety_inspection_point');
CALL sp_safety_fix_code_index('safety_hazard');
CALL sp_safety_fix_code_index('safety_material');
CALL sp_safety_fix_code_index('safety_work_permit');
CALL sp_safety_fix_code_index('safety_accident');
DROP PROCEDURE IF EXISTS sp_safety_fix_code_index;
-- ---------- æ ¡éªŒï¼šç¡®è®¤å·²æ—  uk_code,且有 idx_code ----------
SELECT TABLE_NAME, INDEX_NAME, NON_UNIQUE,
       GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) AS cols
  FROM information_schema.statistics
 WHERE table_schema = DATABASE() AND TABLE_NAME LIKE 'safety%'
   AND INDEX_NAME IN ('uk_code', 'idx_code')
 GROUP BY TABLE_NAME, INDEX_NAME, NON_UNIQUE
 ORDER BY TABLE_NAME;