3e265bd837
- 还原 /v1/public/user/invite_sales 接口及 /invite/sales 别名(与 invite_records 并存) 逻辑/handler/types 与197fed7d删除前版本完全一致,按fefbd4f5新 routes 结构注册 - 新增迁移 02155_promo_schema_fix: 幂等修复 subscribe_promo / order 列类型与索引偏差 - 同步 etc/ppanel.yaml 数据库连接配置 - 补齐相关需求与设计文档
242 lines
8.2 KiB
SQL
242 lines
8.2 KiB
SQL
-- 02155 Promo Schema Fix
|
||
--
|
||
-- 修复历史环境中 02154 未正确执行(或部分 GORM AutoMigrate 推断)导致的
|
||
-- promo 系统列类型 / 索引偏差。完全幂等:可重复执行。
|
||
--
|
||
-- 覆盖偏差:
|
||
-- 1) subscribe_promo.quantity 实际 int/NULL -> BIGINT NOT NULL DEFAULT 1
|
||
-- 2) subscribe_promo 唯一索引 实际 (subscribe_id, promo_rule_id) -> (subscribe_id, quantity, promo_rule_id)
|
||
-- 3) order.promo_rule_id 实际 int/NULL -> BIGINT UNSIGNED NOT NULL DEFAULT 0
|
||
-- 4) order.promo_discount 实际 varchar(255)/NULL -> BIGINT NOT NULL DEFAULT 0
|
||
--
|
||
-- 设计原则:
|
||
-- - 所有 ALTER 前先做 NULL/空串兜底,避免 NOT NULL 转换失败。
|
||
-- - 类型已经正确的环境(02154 正常跑过)不会被改动,所有 IF 判断都基于
|
||
-- INFORMATION_SCHEMA 当前真实状态。
|
||
-- - 索引差异处理 4 个分支:仅当索引确实是错的旧形态时才替换,已经是新形态则不动。
|
||
|
||
|
||
-- ============================================================================
|
||
-- 1) subscribe_promo.quantity
|
||
-- ============================================================================
|
||
|
||
-- 1.1 列不存在则补建(极端历史环境兜底)
|
||
SET @col_exists = (
|
||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE()
|
||
AND TABLE_NAME = 'subscribe_promo'
|
||
AND COLUMN_NAME = 'quantity'
|
||
);
|
||
|
||
SET @sql = IF(
|
||
@col_exists = 0,
|
||
'ALTER TABLE `subscribe_promo` ADD COLUMN `quantity` BIGINT NOT NULL DEFAULT 1 COMMENT ''购买数量'' AFTER `subscribe_id`',
|
||
'SELECT ''subscribe_promo.quantity exists, skip ADD'''
|
||
);
|
||
PREPARE stmt FROM @sql;
|
||
EXECUTE stmt;
|
||
DEALLOCATE PREPARE stmt;
|
||
|
||
-- 1.2 NULL 兜底为 1(旧 AutoMigrate 推断列允许 NULL,必须先回填再 NOT NULL)
|
||
UPDATE `subscribe_promo` SET `quantity` = 1 WHERE `quantity` IS NULL;
|
||
|
||
-- 1.3 类型 / 可空 / 默认值修正:只在与目标定义不一致时改
|
||
SET @col_def_wrong = (
|
||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE()
|
||
AND TABLE_NAME = 'subscribe_promo'
|
||
AND COLUMN_NAME = 'quantity'
|
||
AND (
|
||
LOWER(DATA_TYPE) <> 'bigint'
|
||
OR IS_NULLABLE = 'YES'
|
||
OR COLUMN_DEFAULT IS NULL
|
||
OR COLUMN_DEFAULT <> '1'
|
||
)
|
||
);
|
||
|
||
SET @sql = IF(
|
||
@col_def_wrong = 1,
|
||
'ALTER TABLE `subscribe_promo` MODIFY COLUMN `quantity` BIGINT NOT NULL DEFAULT 1 COMMENT ''购买数量''',
|
||
'SELECT ''subscribe_promo.quantity already matches target definition'''
|
||
);
|
||
PREPARE stmt FROM @sql;
|
||
EXECUTE stmt;
|
||
DEALLOCATE PREPARE stmt;
|
||
|
||
|
||
-- ============================================================================
|
||
-- 2) subscribe_promo 唯一索引:旧形态 -> (subscribe_id, quantity, promo_rule_id)
|
||
-- ============================================================================
|
||
|
||
-- 2.1 删除已知的所有旧形态唯一索引(如果存在)
|
||
SET @idx_exists = (
|
||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
|
||
WHERE TABLE_SCHEMA = DATABASE()
|
||
AND TABLE_NAME = 'subscribe_promo'
|
||
AND INDEX_NAME = 'idx_subscribe_rule'
|
||
);
|
||
SET @sql = IF(
|
||
@idx_exists = 1,
|
||
'ALTER TABLE `subscribe_promo` DROP INDEX `idx_subscribe_rule`',
|
||
'SELECT ''subscribe_promo.idx_subscribe_rule absent'''
|
||
);
|
||
PREPARE stmt FROM @sql;
|
||
EXECUTE stmt;
|
||
DEALLOCATE PREPARE stmt;
|
||
|
||
SET @idx_exists = (
|
||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
|
||
WHERE TABLE_SCHEMA = DATABASE()
|
||
AND TABLE_NAME = 'subscribe_promo'
|
||
AND INDEX_NAME = 'uk_subscribe_rule'
|
||
);
|
||
SET @sql = IF(
|
||
@idx_exists = 1,
|
||
'ALTER TABLE `subscribe_promo` DROP INDEX `uk_subscribe_rule`',
|
||
'SELECT ''subscribe_promo.uk_subscribe_rule absent'''
|
||
);
|
||
PREPARE stmt FROM @sql;
|
||
EXECUTE stmt;
|
||
DEALLOCATE PREPARE stmt;
|
||
|
||
SET @idx_exists = (
|
||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
|
||
WHERE TABLE_SCHEMA = DATABASE()
|
||
AND TABLE_NAME = 'subscribe_promo'
|
||
AND INDEX_NAME = 'uk_subscribe_qty_rule'
|
||
);
|
||
SET @sql = IF(
|
||
@idx_exists = 1,
|
||
'ALTER TABLE `subscribe_promo` DROP INDEX `uk_subscribe_qty_rule`',
|
||
'SELECT ''subscribe_promo.uk_subscribe_qty_rule absent'''
|
||
);
|
||
PREPARE stmt FROM @sql;
|
||
EXECUTE stmt;
|
||
DEALLOCATE PREPARE stmt;
|
||
|
||
-- 2.2 新建目标唯一索引(缺失时才建)
|
||
SET @idx_exists = (
|
||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
|
||
WHERE TABLE_SCHEMA = DATABASE()
|
||
AND TABLE_NAME = 'subscribe_promo'
|
||
AND INDEX_NAME = 'uk_subscribe_quantity_rule'
|
||
);
|
||
SET @sql = IF(
|
||
@idx_exists = 0,
|
||
'ALTER TABLE `subscribe_promo` ADD UNIQUE KEY `uk_subscribe_quantity_rule` (`subscribe_id`, `quantity`, `promo_rule_id`)',
|
||
'SELECT ''subscribe_promo.uk_subscribe_quantity_rule exists'''
|
||
);
|
||
PREPARE stmt FROM @sql;
|
||
EXECUTE stmt;
|
||
DEALLOCATE PREPARE stmt;
|
||
|
||
|
||
-- ============================================================================
|
||
-- 3) order.promo_rule_id -> BIGINT UNSIGNED NOT NULL DEFAULT 0
|
||
-- ============================================================================
|
||
|
||
SET @col_exists = (
|
||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE()
|
||
AND TABLE_NAME = 'order'
|
||
AND COLUMN_NAME = 'promo_rule_id'
|
||
);
|
||
|
||
SET @sql = IF(
|
||
@col_exists = 0,
|
||
'ALTER TABLE `order` ADD COLUMN `promo_rule_id` BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''促销规则ID, 0=未使用促销'' AFTER `discount`',
|
||
'SELECT ''order.promo_rule_id exists, skip ADD'''
|
||
);
|
||
PREPARE stmt FROM @sql;
|
||
EXECUTE stmt;
|
||
DEALLOCATE PREPARE stmt;
|
||
|
||
UPDATE `order` SET `promo_rule_id` = 0 WHERE `promo_rule_id` IS NULL;
|
||
|
||
SET @col_def_wrong = (
|
||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE()
|
||
AND TABLE_NAME = 'order'
|
||
AND COLUMN_NAME = 'promo_rule_id'
|
||
AND (
|
||
LOWER(DATA_TYPE) <> 'bigint'
|
||
OR INSTR(LOWER(COLUMN_TYPE), 'unsigned') = 0
|
||
OR IS_NULLABLE = 'YES'
|
||
OR COLUMN_DEFAULT IS NULL
|
||
OR COLUMN_DEFAULT <> '0'
|
||
)
|
||
);
|
||
|
||
SET @sql = IF(
|
||
@col_def_wrong = 1,
|
||
'ALTER TABLE `order` MODIFY COLUMN `promo_rule_id` BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''促销规则ID, 0=未使用促销''',
|
||
'SELECT ''order.promo_rule_id already matches target definition'''
|
||
);
|
||
PREPARE stmt FROM @sql;
|
||
EXECUTE stmt;
|
||
DEALLOCATE PREPARE stmt;
|
||
|
||
|
||
-- ============================================================================
|
||
-- 4) order.promo_discount -> BIGINT NOT NULL DEFAULT 0
|
||
-- 历史 AutoMigrate 推断为 varchar(255)/NULL,金额字段错存为字符串。
|
||
-- 必须先把空串/NULL 兜底为 '0',再 MODIFY,否则 MySQL 转 BIGINT 会写 0
|
||
-- (这里我们仍兜底显式化,避免触发 strict mode 报错)。
|
||
-- ============================================================================
|
||
|
||
SET @col_exists = (
|
||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE()
|
||
AND TABLE_NAME = 'order'
|
||
AND COLUMN_NAME = 'promo_discount'
|
||
);
|
||
|
||
SET @sql = IF(
|
||
@col_exists = 0,
|
||
'ALTER TABLE `order` ADD COLUMN `promo_discount` BIGINT NOT NULL DEFAULT 0 COMMENT ''促销优惠金额(分)'' AFTER `promo_rule_id`',
|
||
'SELECT ''order.promo_discount exists, skip ADD'''
|
||
);
|
||
PREPARE stmt FROM @sql;
|
||
EXECUTE stmt;
|
||
DEALLOCATE PREPARE stmt;
|
||
|
||
-- 当且仅当当前是字符串型时做兜底(避免对已经是 BIGINT 的环境跑无谓 UPDATE)
|
||
SET @col_is_string = (
|
||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE()
|
||
AND TABLE_NAME = 'order'
|
||
AND COLUMN_NAME = 'promo_discount'
|
||
AND LOWER(DATA_TYPE) IN ('varchar', 'char', 'text')
|
||
);
|
||
|
||
SET @sql = IF(
|
||
@col_is_string = 1,
|
||
'UPDATE `order` SET `promo_discount` = ''0'' WHERE `promo_discount` IS NULL OR `promo_discount` = ''''',
|
||
'SELECT ''order.promo_discount not string type, skip backfill'''
|
||
);
|
||
PREPARE stmt FROM @sql;
|
||
EXECUTE stmt;
|
||
DEALLOCATE PREPARE stmt;
|
||
|
||
SET @col_def_wrong = (
|
||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE()
|
||
AND TABLE_NAME = 'order'
|
||
AND COLUMN_NAME = 'promo_discount'
|
||
AND (
|
||
LOWER(DATA_TYPE) <> 'bigint'
|
||
OR IS_NULLABLE = 'YES'
|
||
OR COLUMN_DEFAULT IS NULL
|
||
OR COLUMN_DEFAULT <> '0'
|
||
)
|
||
);
|
||
|
||
SET @sql = IF(
|
||
@col_def_wrong = 1,
|
||
'ALTER TABLE `order` MODIFY COLUMN `promo_discount` BIGINT NOT NULL DEFAULT 0 COMMENT ''促销优惠金额(分)''',
|
||
'SELECT ''order.promo_discount already matches target definition'''
|
||
);
|
||
PREPARE stmt FROM @sql;
|
||
EXECUTE stmt;
|
||
DEALLOCATE PREPARE stmt;
|