1.0.517.verify.sql 6.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. -- 1.0.517.verify.sql — 每条 SELECT 都必须返回 1
  2. -- ── B1 · 三列到位、类型/可空性符合仓库约定 ─────────────────────────────────────────
  3. SELECT (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE()
  4. AND TABLE_NAME = 'dwd_requirement_examine_detail'
  5. AND COLUMN_NAME IN ('bom_level','material_role','is_current_flag')) = 3;
  6. SELECT (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE()
  7. AND TABLE_NAME = 'dwd_requirement_examine_detail' AND COLUMN_NAME = 'bom_level'
  8. AND DATA_TYPE = 'int' AND IS_NULLABLE = 'YES') = 1;
  9. -- 用 DATA_TYPE + CHARACTER_MAXIMUM_LENGTH 而不是 COLUMN_TYPE 字符串比较:
  10. -- information_schema 在部分 MySQL 版本上是 utf8mb3,对它强加 COLLATE utf8mb4_bin 会直接报
  11. -- "COLLATION 'utf8mb4_bin' is not valid for CHARACTER SET 'utf8mb3'",让 verify 脚本自己把启动打挂。
  12. -- 这两个列是数值/枚举型元数据,不需要区分大小写的比较。
  13. SELECT (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE()
  14. AND TABLE_NAME = 'dwd_requirement_examine_detail' AND COLUMN_NAME = 'material_role'
  15. AND DATA_TYPE = 'varchar' AND CHARACTER_MAXIMUM_LENGTH = 32 AND IS_NULLABLE = 'YES') = 1;
  16. -- 布尔列必须是 tinyint NOT NULL DEFAULT 0(仓库约定:<noun>_flag,不用 bit、不用 is_* 裸名)
  17. SELECT (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE()
  18. AND TABLE_NAME = 'dwd_requirement_examine_detail' AND COLUMN_NAME = 'is_current_flag'
  19. AND DATA_TYPE = 'tinyint' AND IS_NULLABLE = 'NO' AND COLUMN_DEFAULT = '0') = 1;
  20. -- 不得引入 bit 类型的布尔列
  21. SELECT (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE()
  22. AND TABLE_NAME = 'dwd_requirement_examine_detail' AND DATA_TYPE = 'bit') = 0;
  23. -- 不得混入 S8 专属列(本表是通用中台权威表,不给单一消费方开后门)
  24. SELECT (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE()
  25. AND TABLE_NAME = 'dwd_requirement_examine_detail'
  26. AND (COLUMN_NAME LIKE 's8/_%' ESCAPE '/' OR COLUMN_NAME LIKE '%/_s8/_%' ESCAPE '/'
  27. OR COLUMN_NAME IN ('exception_id','rule_code','watch_id'))) = 0;
  28. -- ── B1 · 索引支撑 (tenant_id, is_current_flag, morder_no) ───────────────────────────
  29. SELECT IFNULL((SELECT GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) FROM information_schema.STATISTICS
  30. WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'dwd_requirement_examine_detail'
  31. AND INDEX_NAME = 'idx_req_exam_current'), '')
  32. = 'tenant_id,is_current_flag,morder_no';
  33. -- ── B3 · 标准列契约已写进 schema,且未新增别名/重算列 ───────────────────────────────
  34. SELECT (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE()
  35. AND TABLE_NAME = 'dwd_requirement_examine_detail'
  36. AND COLUMN_NAME IN ('need_count','use_qty','lack_qty')
  37. AND COLUMN_COMMENT LIKE '标准列%') = 3;
  38. SELECT (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE()
  39. AND TABLE_NAME = 'dwd_requirement_examine_detail'
  40. AND COLUMN_NAME IN ('required_qty','satisfied_qty','shortage_qty')) = 0;
  41. -- ── B3 · 齐套恒等式 lack + use = need 在现存数据上成立(空表也算通过)─────────────────
  42. SELECT (SELECT COUNT(*) FROM `dwd_requirement_examine_detail`
  43. WHERE ABS(IFNULL(`lack_qty`,0) + IFNULL(`use_qty`,0) - IFNULL(`need_count`,0)) > 0.0001) = 0;
  44. -- ── B7 · 前修行已清空(material_role IS NULL 精确等价于前修行)───────────────────────
  45. SELECT (SELECT COUNT(*) FROM `dwd_requirement_examine_detail` WHERE `material_role` IS NULL) = 0;
  46. -- ── B2 · 角色取值只允许两个枚举,且永不为空 ─────────────────────────────────────────
  47. SELECT (SELECT COUNT(*) FROM `dwd_requirement_examine_detail`
  48. WHERE `material_role` NOT IN ('FINISHED_GOOD_ROOT','INPUT_MATERIAL')) = 0;
  49. -- ── B2 · level 与角色一致:bom_level=1 必为根,bom_level<>1 必为投入料 ────────────────
  50. SELECT (SELECT COUNT(*) FROM `dwd_requirement_examine_detail`
  51. WHERE (`bom_level` = 1 AND `material_role` <> 'FINISHED_GOOD_ROOT')
  52. OR (`bom_level` <> 1 AND `material_role` <> 'INPUT_MATERIAL')) = 0;
  53. -- bom_level 为 NULL(脏值/缺失)时必须保守落 INPUT_MATERIAL,绝不能落成根
  54. SELECT (SELECT COUNT(*) FROM `dwd_requirement_examine_detail`
  55. WHERE `bom_level` IS NULL AND `material_role` <> 'INPUT_MATERIAL') = 0;
  56. -- ── B4 · 每个 (tenant, 归一 factory) 作用域内最多只有一个 current 批次 ────────────────
  57. -- factory_id 必须归一后再分组:实测存量里 296189/1019060 行 factory_id IS NULL,
  58. -- 且 594/3439 个批次同时含 factory_id=1 与 NULL,不归一会漏掉半个批次。
  59. SELECT (SELECT COUNT(*) FROM (
  60. SELECT `tenant_id`, COALESCE(NULLIF(`factory_id`,0),1) AS f
  61. FROM `dwd_requirement_examine_detail`
  62. WHERE `is_current_flag` = 1
  63. GROUP BY 1, 2
  64. HAVING COUNT(DISTINCT `calc_batch_id`) > 1) x) = 0;
  65. -- is_current_flag 只允许 0/1
  66. SELECT (SELECT COUNT(*) FROM `dwd_requirement_examine_detail`
  67. WHERE `is_current_flag` NOT IN (0,1)) = 0;
  68. -- ── 1.0.356 建立的作用域 CHECK 必须仍在(本批不得把它改掉)──────────────────────────
  69. SELECT (SELECT COUNT(*) FROM information_schema.TABLE_CONSTRAINTS
  70. WHERE CONSTRAINT_SCHEMA = DATABASE() AND TABLE_NAME = 'dwd_requirement_examine_detail'
  71. AND CONSTRAINT_NAME = 'ck_dwd_requirement_valid_scope') = 1;
  72. -- 原有唯一键未被本批动过
  73. SELECT IFNULL((SELECT GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) FROM information_schema.STATISTICS
  74. WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'dwd_requirement_examine_detail'
  75. AND INDEX_NAME = 'uk_dwd_req_exam_detail' AND NON_UNIQUE = 0), '')
  76. = 'tenant_id,row_id,calc_batch_id';