Files
hi-server/initialize/migrate/database/02155_promo_schema_fix.up.sql
T
shanshanzhong147 3e265bd837
Build docker and publish / build (20.15.1) (push) Failing after 13m47s
Build docker and publish / build (20.15.1) (pull_request) Failing after 15m7s
新功能: 还原 v1/public/user/invite_sales 接口 + promo schema 修复迁移
- 还原 /v1/public/user/invite_sales 接口及 /invite/sales 别名(与 invite_records 并存)
  逻辑/handler/types 与 197fed7d 删除前版本完全一致,按 fefbd4f5 新 routes 结构注册
- 新增迁移 02155_promo_schema_fix: 幂等修复 subscribe_promo / order 列类型与索引偏差
- 同步 etc/ppanel.yaml 数据库连接配置
- 补齐相关需求与设计文档
2026-05-28 20:46:37 -07:00

242 lines
8.2 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- 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;