-- 企业优惠快照改造(order库):三张订单表新增「企业优惠方式/折扣率/计费模板」快照列 -- 目的: -- 企业账户(白名单/企业卡/VIN)订单建单时把当时生效的公司优惠设置固化到订单快照列; -- 结算与补偿重算时优先读订单快照(快照为空的历史订单才实时查询并回填),保证: -- 1) 建单后公司优惠设置变更(换折扣率/换模板)不影响历史订单的结算金额与对账口径; -- 2) 方式3(按优惠单价收费)的计费模板被修改/删除时,补偿重算与首次结算口径一致,不降级为原价。 -- 新增列(允许 NULL,历史订单走「实时查询 + 回填」兼容路径): -- preferential_type 企业优惠方式快照(1=不优惠,2=按比例优惠,3=按优惠单价收费) -- service_discount_rate 服务费优惠比例快照(%,方式2使用) -- billing_template_id 计费模板ID快照(方式3使用) -- billing_template_snapshot 计费模板明细快照JSON(方式3使用,抵抗模板后续变更/删除) -- preferential_snapshot_time 优惠快照固化时间 -- 创建日期: 2026-09-30 -- 目标库:charging_pile_order -- 分片表:t_charging_order、t_vin_charging_order、t_card_charging_order(Mycat 逻辑表,物理分表逐片执行) -- 执行方式: -- 1) 首选「小节 A」经数据库代理(MyCat 8066)执行,代理会把 DDL 广播到全部物理分表; -- 2) 代理不支持分片表 DDL 时,改用「小节 B」直连后端 MySQL 实例执行(存储过程,逐物理分表,幂等); -- 3) 最后执行「小节 C」回查校验。 -- 幂等说明:小节 A 为裸 ALTER,重复执行会报 Duplicate column,忽略即可(以小节 C 回查为准); -- 小节 B 先查 information_schema 再变更,可重复执行。 -- ============ 小节 A:经代理执行(推荐) ============ USE `charging_pile_order`; ALTER TABLE `t_charging_order` ADD COLUMN `preferential_type` tinyint(4) DEFAULT NULL COMMENT '企业优惠方式快照(1=不优惠,2=按比例优惠,3=按优惠单价收费;NULL=建单时未固化)', ADD COLUMN `service_discount_rate` decimal(5,2) DEFAULT NULL COMMENT '服务费优惠比例快照(%,方式2使用)', ADD COLUMN `billing_template_id` int(11) DEFAULT NULL COMMENT '计费模板ID快照(方式3使用)', ADD COLUMN `billing_template_snapshot` text COMMENT '计费模板明细快照JSON(方式3使用,抵抗模板后续变更/删除)', ADD COLUMN `preferential_snapshot_time` datetime DEFAULT NULL COMMENT '优惠快照固化时间'; ALTER TABLE `t_vin_charging_order` ADD COLUMN `preferential_type` tinyint(4) DEFAULT NULL COMMENT '企业优惠方式快照(1=不优惠,2=按比例优惠,3=按优惠单价收费;NULL=建单时未固化)', ADD COLUMN `service_discount_rate` decimal(5,2) DEFAULT NULL COMMENT '服务费优惠比例快照(%,方式2使用)', ADD COLUMN `billing_template_id` int(11) DEFAULT NULL COMMENT '计费模板ID快照(方式3使用)', ADD COLUMN `billing_template_snapshot` text COMMENT '计费模板明细快照JSON(方式3使用,抵抗模板后续变更/删除)', ADD COLUMN `preferential_snapshot_time` datetime DEFAULT NULL COMMENT '优惠快照固化时间'; ALTER TABLE `t_card_charging_order` ADD COLUMN `preferential_type` tinyint(4) DEFAULT NULL COMMENT '企业优惠方式快照(1=不优惠,2=按比例优惠,3=按优惠单价收费;NULL=建单时未固化)', ADD COLUMN `service_discount_rate` decimal(5,2) DEFAULT NULL COMMENT '服务费优惠比例快照(%,方式2使用)', ADD COLUMN `billing_template_id` int(11) DEFAULT NULL COMMENT '计费模板ID快照(方式3使用)', ADD COLUMN `billing_template_snapshot` text COMMENT '计费模板明细快照JSON(方式3使用,抵抗模板后续变更/删除)', ADD COLUMN `preferential_snapshot_time` datetime DEFAULT NULL COMMENT '优惠快照固化时间'; -- ============ 小节 B:直连后端 MySQL 实例执行(代理不可用时分表执行,幂等) ============ USE `charging_pile_order`; DROP PROCEDURE IF EXISTS `add_company_preferential_snapshot`; DELIMITER $$ CREATE PROCEDURE `add_company_preferential_snapshot`() BEGIN DECLARE done INT DEFAULT 0; DECLARE target_table VARCHAR(64); DECLARE column_exists INT DEFAULT 0; -- 覆盖逻辑表(若物理存在)与 TBPARTITION 物理分表 DECLARE table_cursor CURSOR FOR SELECT t.table_name FROM information_schema.tables t WHERE t.table_schema = DATABASE() AND t.table_name REGEXP '^t_charging_order(_[0-9]+)?$|^t_vin_charging_order(_[0-9]+)?$|^t_card_charging_order(_[0-9]+)?$'; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; OPEN table_cursor; table_loop: LOOP FETCH table_cursor INTO target_table; IF done = 1 THEN LEAVE table_loop; END IF; SELECT COUNT(*) INTO column_exists FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = target_table AND column_name = 'preferential_type'; IF column_exists = 0 THEN SET @ddl = CONCAT('ALTER TABLE `', target_table, '` ADD COLUMN `preferential_type` tinyint(4) DEFAULT NULL COMMENT ''企业优惠方式快照(1=不优惠,2=按比例优惠,3=按优惠单价收费;NULL=建单时未固化)'''); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; END IF; SELECT COUNT(*) INTO column_exists FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = target_table AND column_name = 'service_discount_rate'; IF column_exists = 0 THEN SET @ddl = CONCAT('ALTER TABLE `', target_table, '` ADD COLUMN `service_discount_rate` decimal(5,2) DEFAULT NULL COMMENT ''服务费优惠比例快照(%,方式2使用)'''); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; END IF; SELECT COUNT(*) INTO column_exists FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = target_table AND column_name = 'billing_template_id'; IF column_exists = 0 THEN SET @ddl = CONCAT('ALTER TABLE `', target_table, '` ADD COLUMN `billing_template_id` int(11) DEFAULT NULL COMMENT ''计费模板ID快照(方式3使用)'''); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; END IF; SELECT COUNT(*) INTO column_exists FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = target_table AND column_name = 'billing_template_snapshot'; IF column_exists = 0 THEN SET @ddl = CONCAT('ALTER TABLE `', target_table, '` ADD COLUMN `billing_template_snapshot` text COMMENT ''计费模板明细快照JSON(方式3使用,抵抗模板后续变更/删除)'''); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; END IF; SELECT COUNT(*) INTO column_exists FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = target_table AND column_name = 'preferential_snapshot_time'; IF column_exists = 0 THEN SET @ddl = CONCAT('ALTER TABLE `', target_table, '` ADD COLUMN `preferential_snapshot_time` datetime DEFAULT NULL COMMENT ''优惠快照固化时间'''); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; END IF; END LOOP; CLOSE table_cursor; END$$ DELIMITER ; CALL `add_company_preferential_snapshot`(); DROP PROCEDURE IF EXISTS `add_company_preferential_snapshot`; -- ============ 小节 C:回查校验 ============ -- 1) 列存在性与注释(三张订单表均应覆盖逻辑表与全部物理分表): -- SELECT table_name, column_name, column_type, column_comment -- FROM information_schema.columns -- WHERE table_schema = 'charging_pile_order' -- AND column_name IN ('preferential_type', 'service_discount_rate', 'billing_template_id', -- 'billing_template_snapshot', 'preferential_snapshot_time') -- ORDER BY table_name, column_name; -- 预期:三张订单表及各自物理分表均存在 5 列,column_comment 中文无乱码 -- 2) 历史订单快照为空(走实时查询 + 回填兼容路径): -- SELECT COUNT(*) FROM t_charging_order WHERE preferential_type IS NULL; -- 预期:等于存量订单数