2026-10-11-market-freight-indexes.sql 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. -- 市场移动端运费批次查询与并发关联约束(MySQL 5.7,幂等)。
  2. -- 若存量数据冲突或同名对象定义错误则明确中止,不静默移动/删除数据。
  3. SET NAMES utf8mb4;
  4. DELIMITER $$
  5. DROP PROCEDURE IF EXISTS `ensure_market_freight_indexes`$$
  6. CREATE PROCEDURE `ensure_market_freight_indexes`()
  7. BEGIN
  8. DECLARE duplicate_rows INT DEFAULT 0;
  9. DECLARE object_count INT DEFAULT 0;
  10. DECLARE index_non_unique INT DEFAULT 1;
  11. DECLARE index_columns VARCHAR(512) DEFAULT '';
  12. DECLARE index_prefix_count INT DEFAULT 0;
  13. DECLARE index_type_count INT DEFAULT 0;
  14. DECLARE index_type_name VARCHAR(32) DEFAULT '';
  15. DECLARE generated_extra VARCHAR(255) DEFAULT '';
  16. DECLARE generated_expression TEXT;
  17. DECLARE normalized_generation_expression TEXT;
  18. DECLARE generated_data_type VARCHAR(64) DEFAULT '';
  19. DECLARE generated_length BIGINT DEFAULT 0;
  20. DECLARE generated_nullable VARCHAR(3) DEFAULT '';
  21. DECLARE exact_freight_unique_indexes INT DEFAULT 0;
  22. SELECT COUNT(*) INTO duplicate_rows
  23. FROM (
  24. SELECT tenant_no, freight_no
  25. FROM biz_sample_freight
  26. GROUP BY tenant_no, freight_no
  27. HAVING COUNT(*) > 1
  28. ) duplicate_freights;
  29. IF duplicate_rows > 0 THEN
  30. SIGNAL SQLSTATE '45000'
  31. SET MESSAGE_TEXT = 'duplicate freight numbers found; reconcile them before rerunning migration';
  32. END IF;
  33. SELECT COUNT(*) INTO duplicate_rows
  34. FROM (
  35. SELECT tenant_no, sample_source, sample_id
  36. FROM biz_sample_freight_item
  37. WHERE del_flag = 0
  38. GROUP BY tenant_no, sample_source, sample_id
  39. HAVING COUNT(*) > 1
  40. ) duplicate_active_links;
  41. IF duplicate_rows > 0 THEN
  42. SIGNAL SQLSTATE '45000'
  43. SET MESSAGE_TEXT = 'duplicate active sample freight links found; reconcile them before rerunning migration';
  44. END IF;
  45. SELECT COUNT(*) INTO object_count
  46. FROM information_schema.COLUMNS
  47. WHERE TABLE_SCHEMA = DATABASE()
  48. AND TABLE_NAME = 'biz_sample_freight_item'
  49. AND COLUMN_NAME = 'active_sample_key';
  50. IF object_count = 0 THEN
  51. ALTER TABLE biz_sample_freight_item
  52. ADD COLUMN active_sample_key VARCHAR(170)
  53. GENERATED ALWAYS AS (
  54. IF(del_flag = 0, CONCAT(tenant_no, '#', sample_source, '#', sample_id), NULL)
  55. ) STORED;
  56. ELSE
  57. SELECT EXTRA, GENERATION_EXPRESSION, DATA_TYPE,
  58. CHARACTER_MAXIMUM_LENGTH, IS_NULLABLE
  59. INTO generated_extra, generated_expression, generated_data_type,
  60. generated_length, generated_nullable
  61. FROM information_schema.COLUMNS
  62. WHERE TABLE_SCHEMA = DATABASE()
  63. AND TABLE_NAME = 'biz_sample_freight_item'
  64. AND COLUMN_NAME = 'active_sample_key';
  65. SET normalized_generation_expression = LOWER(
  66. REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
  67. COALESCE(generated_expression, ''),
  68. '`', ''), ' ', ''), CHAR(9), ''), CHAR(10), ''), '(', ''), ')', '')
  69. );
  70. IF UPPER(COALESCE(generated_extra, '')) NOT LIKE '%STORED GENERATED%'
  71. OR LOWER(COALESCE(generated_data_type, '')) <> 'varchar'
  72. OR COALESCE(generated_length, 0) <> 170
  73. OR UPPER(COALESCE(generated_nullable, '')) <> 'YES'
  74. OR normalized_generation_expression <>
  75. 'ifdel_flag=0,concattenant_no,''#'',sample_source,''#'',sample_id,null' THEN
  76. SIGNAL SQLSTATE '45000'
  77. SET MESSAGE_TEXT = 'wrong active_sample_key type/expression; drop column and dependent index, then rerun migration';
  78. END IF;
  79. END IF;
  80. SELECT COUNT(*), COALESCE(MIN(NON_UNIQUE), 1),
  81. COALESCE(GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX SEPARATOR ','), ''),
  82. SUM(CASE WHEN SUB_PART IS NOT NULL THEN 1 ELSE 0 END),
  83. COUNT(DISTINCT INDEX_TYPE), COALESCE(MIN(INDEX_TYPE), '')
  84. INTO object_count, index_non_unique, index_columns,
  85. index_prefix_count, index_type_count, index_type_name
  86. FROM information_schema.STATISTICS
  87. WHERE TABLE_SCHEMA = DATABASE()
  88. AND TABLE_NAME = 'biz_sample_freight_item'
  89. AND INDEX_NAME = 'uk_bsfi_active_sample';
  90. IF object_count = 0 THEN
  91. ALTER TABLE biz_sample_freight_item
  92. ADD UNIQUE INDEX uk_bsfi_active_sample (active_sample_key);
  93. ELSEIF object_count <> 1 OR index_non_unique <> 0
  94. OR index_columns <> 'active_sample_key' OR index_prefix_count <> 0
  95. OR index_type_count <> 1 OR index_type_name <> 'BTREE' THEN
  96. SIGNAL SQLSTATE '45000'
  97. SET MESSAGE_TEXT = 'wrong index uk_bsfi_active_sample; drop it and rerun migration';
  98. END IF;
  99. -- 旧迁移已创建 uk_sample_freight_tenant_no;任何名称的等价精确唯一索引均复用。
  100. -- 但若本迁移预留名称已存在且定义错误,必须先修复,不能静默绕过。
  101. SELECT COUNT(*), COALESCE(MIN(NON_UNIQUE), 1),
  102. COALESCE(GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX SEPARATOR ','), ''),
  103. SUM(CASE WHEN SUB_PART IS NOT NULL THEN 1 ELSE 0 END),
  104. COUNT(DISTINCT INDEX_TYPE), COALESCE(MIN(INDEX_TYPE), '')
  105. INTO object_count, index_non_unique, index_columns,
  106. index_prefix_count, index_type_count, index_type_name
  107. FROM information_schema.STATISTICS
  108. WHERE TABLE_SCHEMA = DATABASE()
  109. AND TABLE_NAME = 'biz_sample_freight'
  110. AND INDEX_NAME = 'uk_bsf_tenant_freight_no';
  111. IF object_count > 0 AND (object_count <> 2 OR index_non_unique <> 0
  112. OR index_columns <> 'tenant_no,freight_no' OR index_prefix_count <> 0
  113. OR index_type_count <> 1 OR index_type_name <> 'BTREE') THEN
  114. SIGNAL SQLSTATE '45000'
  115. SET MESSAGE_TEXT = 'wrong index uk_bsf_tenant_freight_no; drop it and rerun migration';
  116. END IF;
  117. SELECT COUNT(*) INTO exact_freight_unique_indexes
  118. FROM (
  119. SELECT INDEX_NAME
  120. FROM information_schema.STATISTICS
  121. WHERE TABLE_SCHEMA = DATABASE()
  122. AND TABLE_NAME = 'biz_sample_freight'
  123. GROUP BY INDEX_NAME
  124. HAVING MIN(NON_UNIQUE) = 0
  125. AND MAX(NON_UNIQUE) = 0
  126. AND GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX SEPARATOR ',') =
  127. 'tenant_no,freight_no'
  128. AND SUM(CASE WHEN SUB_PART IS NOT NULL THEN 1 ELSE 0 END) = 0
  129. AND COUNT(DISTINCT INDEX_TYPE) = 1
  130. AND MIN(INDEX_TYPE) = 'BTREE'
  131. ) exact_freight_unique_index_definitions;
  132. IF exact_freight_unique_indexes = 0 THEN
  133. ALTER TABLE biz_sample_freight
  134. ADD UNIQUE INDEX uk_bsf_tenant_freight_no (tenant_no, freight_no);
  135. END IF;
  136. SELECT COUNT(*), COALESCE(MIN(NON_UNIQUE), 1),
  137. COALESCE(GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX SEPARATOR ','), ''),
  138. SUM(CASE WHEN SUB_PART IS NOT NULL THEN 1 ELSE 0 END),
  139. COUNT(DISTINCT INDEX_TYPE), COALESCE(MIN(INDEX_TYPE), '')
  140. INTO object_count, index_non_unique, index_columns,
  141. index_prefix_count, index_type_count, index_type_name
  142. FROM information_schema.STATISTICS
  143. WHERE TABLE_SCHEMA = DATABASE()
  144. AND TABLE_NAME = 'biz_sample_freight'
  145. AND INDEX_NAME = 'idx_bsf_market_list';
  146. IF object_count = 0 THEN
  147. ALTER TABLE biz_sample_freight
  148. ADD INDEX idx_bsf_market_list (tenant_no, del_flag, create_time, id);
  149. ELSEIF object_count <> 4 OR index_non_unique <> 1
  150. OR index_columns <> 'tenant_no,del_flag,create_time,id'
  151. OR index_prefix_count <> 0 OR index_type_count <> 1
  152. OR index_type_name <> 'BTREE' THEN
  153. SIGNAL SQLSTATE '45000'
  154. SET MESSAGE_TEXT = 'wrong index idx_bsf_market_list; drop it and rerun migration';
  155. END IF;
  156. SELECT COUNT(*), COALESCE(MIN(NON_UNIQUE), 1),
  157. COALESCE(GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX SEPARATOR ','), ''),
  158. SUM(CASE WHEN SUB_PART IS NOT NULL THEN 1 ELSE 0 END),
  159. COUNT(DISTINCT INDEX_TYPE), COALESCE(MIN(INDEX_TYPE), '')
  160. INTO object_count, index_non_unique, index_columns,
  161. index_prefix_count, index_type_count, index_type_name
  162. FROM information_schema.STATISTICS
  163. WHERE TABLE_SCHEMA = DATABASE()
  164. AND TABLE_NAME = 'biz_sample_freight_item'
  165. AND INDEX_NAME = 'idx_bsfi_market_batch';
  166. IF object_count = 0 THEN
  167. ALTER TABLE biz_sample_freight_item
  168. ADD INDEX idx_bsfi_market_batch (tenant_no, freight_id, del_flag, create_time, id);
  169. ELSEIF object_count <> 5 OR index_non_unique <> 1
  170. OR index_columns <> 'tenant_no,freight_id,del_flag,create_time,id'
  171. OR index_prefix_count <> 0 OR index_type_count <> 1
  172. OR index_type_name <> 'BTREE' THEN
  173. SIGNAL SQLSTATE '45000'
  174. SET MESSAGE_TEXT = 'wrong index idx_bsfi_market_batch; drop it and rerun migration';
  175. END IF;
  176. END$$
  177. CALL `ensure_market_freight_indexes`()$$
  178. DROP PROCEDURE `ensure_market_freight_indexes`$$
  179. DELIMITER ;