205 lines
14 KiB
SQL
205 lines
14 KiB
SQL
-- 生产专用:修复“biz_tunnel 已存在、日期已升级、关联业务表仍为旧结构”的状态。
|
|
-- 依据用户提供的 shierfeng-fastapi / MySQL 8.0.46 SHOW CREATE TABLE;不是通用幂等迁移。
|
|
-- 仅生成,未在本地或生产执行。必须先停写、完整备份、在隔离恢复实例试跑,并经 DBA 审核。
|
|
-- 保留现有 biz_tunnel(包括 ORM 生成的外键/索引名称)和所有物料日期,不重建表、不补造历史。
|
|
-- 本补丁成功后:20261008_shipment_receipt_mysql.sql -> 20261008_usage_fifo_mysql.sql。
|
|
-- 不执行原 20261005_tunnel_material_flow_mysql.sql,也不重复执行日期/全量初始化脚本。
|
|
-- 在同一连接中显式 SET @shierfeng_prod_migration_approved = 1 后才能改业务表。
|
|
-- 该变量是人工确认门,不是环境识别器;同名开发库也必须禁止执行本交付。
|
|
-- 使用 mysql 批处理、禁用 --force;任一错误立即停止,不启动应用、不盲目重跑。
|
|
-- DDL 隐式提交,异常 handler 的 ROLLBACK 只能回滚菜单 DML,不能回滚之前的 ALTER。
|
|
|
|
DELIMITER $$
|
|
CREATE PROCEDURE repair_prod_existing_tunnel_20261008()
|
|
BEGIN
|
|
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
|
BEGIN
|
|
ROLLBACK;
|
|
RESIGNAL;
|
|
END;
|
|
|
|
IF COALESCE(@shierfeng_prod_migration_approved, 0) <> 1 THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Production maintenance approval and verified backup are required';
|
|
END IF;
|
|
IF DATABASE() IS NULL OR DATABASE() <> 'shierfeng-fastapi' THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Select the reviewed shierfeng-fastapi database on the production server';
|
|
END IF;
|
|
IF SUBSTRING_INDEX(VERSION(), '.', 1) <> '8'
|
|
OR (CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(VERSION(), '.', 2), '.', -1) AS UNSIGNED) = 0
|
|
AND CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(VERSION(), '.', 3), '.', -1) AS UNSIGNED) < 16) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'MySQL 8.0.16 or newer MySQL 8 is required';
|
|
END IF;
|
|
|
|
-- 所有前置检查必须在首个业务表 ALTER 之前;不修改不符合快照的数据库。
|
|
IF (SELECT COUNT(*) FROM information_schema.tables
|
|
WHERE table_schema = DATABASE() AND engine = 'InnoDB'
|
|
AND table_name IN ('biz_tunnel', 'biz_test_batch', 'biz_customer_site', 'biz_usage_record',
|
|
'biz_return_item', 'biz_pallet_inventory', 'biz_pallet_event',
|
|
'biz_filling_record', 'biz_shipment_order', 'sys_menu', 'sys_role_menu', 'sys_user')) <> 12 THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Required reviewed InnoDB tables are missing';
|
|
END IF;
|
|
IF (SELECT COUNT(*) FROM information_schema.columns
|
|
WHERE table_schema = DATABASE() AND table_name = 'biz_tunnel'
|
|
AND column_name IN ('tunnel_id', 'test_batch_id', 'site_id', 'tunnel_code', 'tunnel_name',
|
|
'current_trace_no', 'current_trace_started_at', 'status', 'create_by',
|
|
'create_time', 'update_by', 'update_time', 'remark')) <> 13
|
|
OR NOT EXISTS (SELECT 1 FROM information_schema.columns
|
|
WHERE table_schema = DATABASE() AND table_name = 'biz_tunnel'
|
|
AND column_name = 'tunnel_id' AND column_type = 'bigint' AND is_nullable = 'NO') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Existing tunnel table does not match the reviewed structure';
|
|
END IF;
|
|
-- 只校验外键语义,不要求 ORM 外键名等于原手写脚本的名称。
|
|
IF NOT EXISTS (SELECT 1 FROM information_schema.key_column_usage
|
|
WHERE table_schema = DATABASE() AND table_name = 'biz_tunnel'
|
|
AND column_name = 'site_id' AND referenced_table_schema = DATABASE()
|
|
AND referenced_table_name = 'biz_customer_site' AND referenced_column_name = 'site_id')
|
|
OR NOT EXISTS (SELECT 1 FROM information_schema.key_column_usage
|
|
WHERE table_schema = DATABASE() AND table_name = 'biz_tunnel'
|
|
AND column_name = 'test_batch_id' AND referenced_table_schema = DATABASE()
|
|
AND referenced_table_name = 'biz_test_batch' AND referenced_column_name = 'batch_id') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Existing tunnel foreign keys must be reviewed';
|
|
END IF;
|
|
IF NOT EXISTS (SELECT index_name FROM information_schema.statistics
|
|
WHERE table_schema = DATABASE() AND table_name = 'biz_tunnel' AND non_unique = 0
|
|
GROUP BY index_name
|
|
HAVING GROUP_CONCAT(column_name ORDER BY seq_in_index) = 'site_id,tunnel_code') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Existing tunnel site and code unique key is missing';
|
|
END IF;
|
|
IF (SELECT COUNT(*) FROM information_schema.columns
|
|
WHERE table_schema = DATABASE() AND table_name = 'biz_filling_record'
|
|
AND column_name IN ('production_date', 'expiry_date') AND data_type = 'date' AND is_nullable = 'YES') <> 2
|
|
OR NOT EXISTS (SELECT 1 FROM information_schema.table_constraints
|
|
WHERE constraint_schema = DATABASE() AND table_name = 'biz_filling_record'
|
|
AND constraint_name = 'ck_biz_filling_record_material_dates'
|
|
AND constraint_type = 'CHECK' AND enforced = 'YES') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'The reviewed material date migration must already be complete';
|
|
END IF;
|
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
|
WHERE table_schema = DATABASE() AND table_name = 'biz_usage_record'
|
|
AND column_name = 'line_id' AND column_type = 'bigint' AND is_nullable = 'NO') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Usage line_id is not in the reviewed pre-migration state';
|
|
END IF;
|
|
IF EXISTS (SELECT 1 FROM information_schema.columns
|
|
WHERE table_schema = DATABASE()
|
|
AND ((table_name = 'biz_usage_record' AND column_name IN ('tunnel_id', 'trace_no', 'batch_no_snapshot'))
|
|
OR (table_name = 'biz_return_item' AND column_name IN ('tunnel_id_snapshot', 'trace_no_snapshot', 'batch_no_snapshot'))
|
|
OR (table_name = 'biz_pallet_inventory' AND column_name IN ('tunnel_id', 'trace_no', 'site_arrived_at'))
|
|
OR (table_name = 'biz_pallet_event' AND column_name IN ('before_tunnel_id', 'after_tunnel_id', 'trace_no', 'batch_no_snapshot'))
|
|
OR (table_name = 'biz_shipment_order' AND column_name IN ('receipt_state', 'received_by', 'received_at', 'receipt_idempotency_key', 'receipt_request_hash'))
|
|
OR (table_name IN ('biz_usage_record', 'biz_pallet_event') AND column_name IN ('fifo_skip_reason', 'fifo_recommendation')))) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Target columns already exist: partial or completed migration; do not rerun';
|
|
END IF;
|
|
IF NOT EXISTS (SELECT 1 FROM information_schema.check_constraints
|
|
WHERE constraint_schema = DATABASE() AND constraint_name = 'ck_biz_pallet_event_event_type'
|
|
AND UPPER(check_clause) LIKE '%USAGE_RECORDED%'
|
|
AND UPPER(check_clause) NOT LIKE '%TUNNEL_ENTERED%'
|
|
AND UPPER(check_clause) NOT LIKE '%SHIPMENT_RECEIVED%')
|
|
OR NOT EXISTS (SELECT 1 FROM information_schema.check_constraints
|
|
WHERE constraint_schema = DATABASE() AND constraint_name = 'ck_biz_pallet_inventory_flow_state'
|
|
AND UPPER(check_clause) LIKE '%AT_SITE_UNUSED%'
|
|
AND UPPER(check_clause) NOT LIKE '%IN_TRANSIT%') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Event or inventory CHECK differs from the reviewed legacy state';
|
|
END IF;
|
|
IF EXISTS (SELECT 1 FROM information_schema.table_constraints
|
|
WHERE constraint_schema = DATABASE()
|
|
AND constraint_name IN ('fk_biz_usage_record_tunnel', 'fk_biz_return_item_tunnel',
|
|
'fk_biz_pallet_inventory_tunnel', 'fk_biz_pallet_event_before_tunnel',
|
|
'fk_biz_pallet_event_after_tunnel', 'uq_biz_shipment_receipt_site_key',
|
|
'fk_biz_shipment_order_received_by', 'ck_biz_shipment_order_receipt_state')) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'New constraint names already exist; review schema before migration';
|
|
END IF;
|
|
IF EXISTS (SELECT 1 FROM information_schema.routines WHERE routine_schema = DATABASE()
|
|
AND routine_name IN ('migrate_shipment_receipt_20261008', 'migrate_usage_fifo_20261008')) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'A previous receipt or FIFO migration routine remains; inspect before proceeding';
|
|
END IF;
|
|
IF EXISTS (SELECT 1 FROM information_schema.triggers WHERE trigger_schema = DATABASE()
|
|
AND event_object_table IN ('biz_usage_record', 'biz_return_item', 'biz_pallet_inventory',
|
|
'biz_pallet_event', 'biz_shipment_order', 'sys_menu'))
|
|
OR EXISTS (SELECT 1 FROM information_schema.events WHERE event_schema = DATABASE() AND status = 'ENABLED') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Custom triggers or enabled events require separate DBA review';
|
|
END IF;
|
|
IF NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 121 AND parent_id = 0 AND menu_type = 'M')
|
|
OR NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 510 AND parent_id = 122
|
|
AND menu_type = 'C' AND perms = 'business:shipment:list') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Existing parent menus do not match the reviewed deployment';
|
|
END IF;
|
|
IF EXISTS (SELECT 1 FROM sys_menu WHERE menu_id IN (520, 1116, 1117, 1118, 1119)
|
|
OR perms IN ('master:tunnel:list', 'master:tunnel:query', 'master:tunnel:add',
|
|
'master:tunnel:edit', 'business:shipment:receive')) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Tunnel or receipt menu ID/permission conflict; do not overwrite';
|
|
END IF;
|
|
IF EXISTS (SELECT 1 FROM sys_role_menu WHERE menu_id IN (520, 1116, 1117, 1118, 1119)) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Orphan role grants would become active; review before inserting menus';
|
|
END IF;
|
|
|
|
-- BEGIN DDL
|
|
ALTER TABLE biz_usage_record
|
|
ADD COLUMN tunnel_id BIGINT NULL COMMENT '隧道ID;历史记录可能为空' AFTER site_id,
|
|
ADD COLUMN trace_no VARCHAR(64) NULL COMMENT '隧道物料内部溯源号;历史记录可能为空' AFTER tunnel_id,
|
|
ADD COLUMN batch_no_snapshot VARCHAR(64) NULL COMMENT '生产批次快照;历史记录可能为空' AFTER trace_no,
|
|
MODIFY COLUMN line_id BIGINT NULL COMMENT '产线ID(可选)',
|
|
ADD CONSTRAINT fk_biz_usage_record_tunnel FOREIGN KEY (tunnel_id) REFERENCES biz_tunnel (tunnel_id);
|
|
|
|
ALTER TABLE biz_return_item
|
|
ADD COLUMN tunnel_id_snapshot BIGINT NULL COMMENT '申请时隧道ID快照' AFTER active_filling_id_snapshot,
|
|
ADD COLUMN trace_no_snapshot VARCHAR(64) NULL COMMENT '申请时物料溯源号快照' AFTER tunnel_id_snapshot,
|
|
ADD COLUMN batch_no_snapshot VARCHAR(64) NULL COMMENT '申请时生产批次快照' AFTER trace_no_snapshot,
|
|
ADD CONSTRAINT fk_biz_return_item_tunnel FOREIGN KEY (tunnel_id_snapshot) REFERENCES biz_tunnel (tunnel_id);
|
|
|
|
ALTER TABLE biz_pallet_inventory
|
|
ADD COLUMN tunnel_id BIGINT NULL COMMENT '当前隧道ID' AFTER site_id,
|
|
ADD COLUMN trace_no VARCHAR(64) NULL COMMENT '当前隧道物料溯源号' AFTER tunnel_id,
|
|
ADD CONSTRAINT fk_biz_pallet_inventory_tunnel FOREIGN KEY (tunnel_id) REFERENCES biz_tunnel (tunnel_id);
|
|
|
|
ALTER TABLE biz_pallet_event
|
|
ADD COLUMN before_tunnel_id BIGINT NULL COMMENT '变更前隧道ID' AFTER before_site_id,
|
|
ADD COLUMN after_tunnel_id BIGINT NULL COMMENT '变更后隧道ID' AFTER after_site_id,
|
|
ADD COLUMN trace_no VARCHAR(64) NULL COMMENT '事件关联物料溯源号' AFTER after_remaining_packages,
|
|
ADD COLUMN batch_no_snapshot VARCHAR(64) NULL COMMENT '事件生产批次快照' AFTER trace_no,
|
|
ADD CONSTRAINT fk_biz_pallet_event_before_tunnel FOREIGN KEY (before_tunnel_id) REFERENCES biz_tunnel (tunnel_id),
|
|
ADD CONSTRAINT fk_biz_pallet_event_after_tunnel FOREIGN KEY (after_tunnel_id) REFERENCES biz_tunnel (tunnel_id);
|
|
|
|
ALTER TABLE biz_pallet_event
|
|
DROP CHECK ck_biz_pallet_event_event_type,
|
|
ADD CONSTRAINT ck_biz_pallet_event_event_type CHECK (
|
|
event_type IN ('INBOUND_CONFIRMED', 'FILLING_CONFIRMED', 'SHIPMENT_CONFIRMED',
|
|
'TUNNEL_ENTERED', 'USAGE_RECORDED', 'RETURN_REQUESTED', 'RETURN_CONFIRMED')
|
|
);
|
|
-- END DDL
|
|
|
|
-- 菜单只新增已核实空闲的 ID;不修改 sys_role_menu、不自动授予普通角色。
|
|
START TRANSACTION;
|
|
-- BEGIN MENU
|
|
INSERT INTO sys_menu (
|
|
menu_id, menu_name, parent_id, order_num, path, component, query, route_name,
|
|
is_frame, is_cache, menu_type, visible, status, perms, icon, create_by,
|
|
create_time, update_by, update_time, remark
|
|
) VALUES
|
|
(520, '隧道资料', 121, 7, 'tunnel', 'master/tunnel/index', '', '',
|
|
1, 0, 'C', '0', '0', 'master:tunnel:list', '#', 'admin', SYSDATE(), '', NULL, '隧道资料菜单'),
|
|
(1116, '隧道查询', 520, 1, '#', '', '', '',
|
|
1, 0, 'F', '0', '0', 'master:tunnel:query', '#', 'admin', SYSDATE(), '', NULL, ''),
|
|
(1117, '隧道新增', 520, 2, '#', '', '', '',
|
|
1, 0, 'F', '0', '0', 'master:tunnel:add', '#', 'admin', SYSDATE(), '', NULL, ''),
|
|
(1118, '隧道修改', 520, 3, '#', '', '', '',
|
|
1, 0, 'F', '0', '0', 'master:tunnel:edit', '#', 'admin', SYSDATE(), '', NULL, '');
|
|
-- END MENU
|
|
COMMIT;
|
|
END$$
|
|
DELIMITER ;
|
|
|
|
CALL repair_prod_existing_tunnel_20261008();
|
|
DROP PROCEDURE repair_prod_existing_tunnel_20261008;
|
|
SET @shierfeng_prod_migration_approved = NULL;
|
|
|
|
-- 返回12个新增隧道字段、line_id=YES及4行隧道菜单;随后仍须执行收货/FIFO两份补丁。
|
|
SELECT table_name, column_name, column_type, is_nullable
|
|
FROM information_schema.columns
|
|
WHERE table_schema = DATABASE()
|
|
AND ((table_name = 'biz_usage_record' AND column_name IN ('tunnel_id', 'trace_no', 'batch_no_snapshot', 'line_id'))
|
|
OR (table_name = 'biz_return_item' AND column_name IN ('tunnel_id_snapshot', 'trace_no_snapshot', 'batch_no_snapshot'))
|
|
OR (table_name = 'biz_pallet_inventory' AND column_name IN ('tunnel_id', 'trace_no'))
|
|
OR (table_name = 'biz_pallet_event' AND column_name IN ('before_tunnel_id', 'after_tunnel_id', 'trace_no', 'batch_no_snapshot')))
|
|
ORDER BY table_name, ordinal_position;
|
|
SELECT menu_id, parent_id, perms FROM sys_menu WHERE menu_id IN (520, 1116, 1117, 1118) ORDER BY menu_id;
|