1.0.533.verify.sql 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. -- 1.0.533.verify.sql — 每条 SELECT 都必须返回 1
  2. --
  3. -- ⚠️ 本项目的 AutoVersionUpdate 按分号切分本文件,并把【每一个切片】都当断言、要求返回 1。
  4. -- 因此:① 不得放"仅供排查"的 informational 查询(它返回结果集不是 1);
  5. -- ② 文件必须以最后一条断言的分号结尾,**末尾不能留纯注释块** ——
  6. -- 尾部注释会被切成多出来的一条语句,同样导致迁移判失败、后端拒绝启动。
  7. -- 需要看状态分布请另跑独立只读查询,不要写进 verify。
  8. --
  9. -- 结构断言(①~⑤)迁移后即可全过;数据断言(⑥~⑰)在表为空时也成立(COUNT=0),
  10. -- transform 跑过之后才真正有判别力。
  11. -- ── ① 表存在 ────────────────────────────────────────────────────────────────────────
  12. SELECT (SELECT COUNT(*) FROM `information_schema`.`TABLES`
  13. WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'dwd_product_design_kpi') = 1;
  14. -- ── ② Unique Key 正确:必须是 (tenant_id, sales_order_id),且 tenant_id 为首列 ──────
  15. SELECT (SELECT GROUP_CONCAT(`COLUMN_NAME` ORDER BY `SEQ_IN_INDEX`)
  16. FROM `information_schema`.`STATISTICS`
  17. WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'dwd_product_design_kpi'
  18. AND `INDEX_NAME` = 'uk_dwd_product_design_kpi') = 'tenant_id,sales_order_id';
  19. -- ── ③ tenant_id / sales_order_id 必须 NOT NULL ─────────────────────────────────────
  20. SELECT (SELECT COUNT(*) FROM `information_schema`.`COLUMNS`
  21. WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'dwd_product_design_kpi'
  22. AND `COLUMN_NAME` IN ('tenant_id','sales_order_id')
  23. AND `IS_NULLABLE` = 'NO') = 2;
  24. -- ── ④ actual_hours 类型正确(decimal,不能是整型/字符串)──────────────────────────
  25. SELECT (SELECT COUNT(*) FROM `information_schema`.`COLUMNS`
  26. WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'dwd_product_design_kpi'
  27. AND `COLUMN_NAME` = 'actual_hours' AND `DATA_TYPE` = 'decimal') = 1;
  28. -- ── ⑤ 本批不得引入 TargetHours / 红黄绿相关列 ──────────────────────────────────────
  29. SELECT (SELECT COUNT(*) FROM `information_schema`.`COLUMNS`
  30. WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'dwd_product_design_kpi'
  31. AND `COLUMN_NAME` IN ('target_hours','kpi_status','yellow_threshold',
  32. 'red_threshold','achievement_rate')) = 0;
  33. -- ── ⑥ 无非法租户 ───────────────────────────────────────────────────────────────────
  34. SELECT (SELECT COUNT(*) FROM `dwd_product_design_kpi`
  35. WHERE `tenant_id` IS NULL OR `tenant_id` <= 0 OR `sales_order_id` <= 0) = 0;
  36. -- ── ⑦ calculation_status 取值只允许 6 种 ───────────────────────────────────────────
  37. SELECT (SELECT COUNT(*) FROM `dwd_product_design_kpi`
  38. WHERE `calculation_status` NOT IN
  39. ('OK','NOT_STARTED','IN_PROGRESS','END_UNKNOWN','INVALID_NO_START','INVALID_TIME_SEQUENCE')) = 0;
  40. -- ── ⑧ OK 行:start/end 都有值、end > start、actual_hours 有值且与时间差一致 ────────
  41. SELECT (SELECT COUNT(*) FROM `dwd_product_design_kpi`
  42. WHERE `calculation_status` = 'OK'
  43. AND (`product_design_start_time` IS NULL
  44. OR `product_design_end_time` IS NULL
  45. OR `product_design_end_time` <= `product_design_start_time`
  46. OR `actual_hours` IS NULL
  47. OR ABS(`actual_hours` - ROUND(TIMESTAMPDIFF(SECOND,
  48. `product_design_start_time`, `product_design_end_time`) / 3600.0, 2)) > 0.005)) = 0;
  49. -- ── ⑨ END_UNKNOWN 行:end 必须 NULL(严禁用 update_time 伪造历史 End)─────────────
  50. SELECT (SELECT COUNT(*) FROM `dwd_product_design_kpi`
  51. WHERE `calculation_status` = 'END_UNKNOWN' AND `product_design_end_time` IS NOT NULL) = 0;
  52. -- ── ⑩ END_UNKNOWN 行:actual_hours 必须 NULL,且必须确有已下达日计划佐证 ───────────
  53. SELECT (SELECT COUNT(*) FROM `dwd_product_design_kpi`
  54. WHERE `calculation_status` = 'END_UNKNOWN'
  55. AND (`actual_hours` IS NOT NULL
  56. OR `product_design_start_time` IS NULL
  57. OR `has_released_schedule` <> 1)) = 0;
  58. -- ── ⑪ IN_PROGRESS 行:start 有值、end 为 NULL、且【无】已下达日计划佐证 ────────────
  59. -- 这一条是 END_UNKNOWN / IN_PROGRESS 不被混淆的结构性保证
  60. SELECT (SELECT COUNT(*) FROM `dwd_product_design_kpi`
  61. WHERE `calculation_status` = 'IN_PROGRESS'
  62. AND (`product_design_start_time` IS NULL
  63. OR `product_design_end_time` IS NOT NULL
  64. OR `actual_hours` IS NOT NULL
  65. OR `has_released_schedule` <> 0)) = 0;
  66. -- ── ⑫ NOT_STARTED 行:start / end / hours 全 NULL ──────────────────────────────────
  67. SELECT (SELECT COUNT(*) FROM `dwd_product_design_kpi`
  68. WHERE `calculation_status` = 'NOT_STARTED'
  69. AND (`product_design_start_time` IS NOT NULL
  70. OR `product_design_end_time` IS NOT NULL
  71. OR `actual_hours` IS NOT NULL)) = 0;
  72. -- ── ⑬ INVALID_* 行:一律不得给出 actual_hours ──────────────────────────────────────
  73. SELECT (SELECT COUNT(*) FROM `dwd_product_design_kpi`
  74. WHERE `calculation_status` IN ('INVALID_NO_START','INVALID_TIME_SEQUENCE')
  75. AND `actual_hours` IS NOT NULL) = 0;
  76. -- ── ⑭ Start 必须原样取自 Stage-1 DWD,不得自行重算 ─────────────────────────────────
  77. SELECT (SELECT COUNT(*) FROM `dwd_product_design_kpi` p
  78. LEFT JOIN `dwd_order_review_kpi` k
  79. ON k.`tenant_id` = p.`tenant_id` AND k.`sales_order_id` = p.`sales_order_id`
  80. WHERE IFNULL(p.`product_design_start_time`, '1900-01-01')
  81. <> IFNULL(k.`review_end_time`, '1900-01-01')) = 0;
  82. -- ── ⑮ End 必须等于该订单 FIRST SUCCESS 释放事件的 action_end_time(不是 LAST/MAX)──
  83. SELECT (SELECT COUNT(*) FROM `dwd_product_design_kpi` p
  84. WHERE p.`product_design_end_time` IS NOT NULL
  85. AND p.`product_design_end_time` <> (
  86. SELECT MIN(e.`action_end_time`) FROM `mdp_std_action_event` e
  87. WHERE e.`tenant_id` = p.`tenant_id`
  88. AND e.`biz_id` = p.`sales_order_id`
  89. AND e.`action_code` = 'S2_DAILY_PLAN_RELEASE'
  90. AND e.`biz_type` = 'crm_seorder'
  91. AND e.`action_status` = 'SUCCESS')) = 0;
  92. -- ── ⑯ Event Identity 一致:被采纳事件必须真属于同租户同订单 ────────────────────────
  93. SELECT (SELECT COUNT(*) FROM `dwd_product_design_kpi` p
  94. WHERE p.`release_action_run_id` IS NOT NULL
  95. AND NOT EXISTS (
  96. SELECT 1 FROM `mdp_std_action_event` e
  97. WHERE e.`action_run_id` = p.`release_action_run_id`
  98. AND e.`tenant_id` = p.`tenant_id`
  99. AND e.`biz_id` = p.`sales_order_id`
  100. AND e.`action_code` = 'S2_DAILY_PLAN_RELEASE'
  101. AND e.`action_status` = 'SUCCESS')) = 0;
  102. -- ── ⑰ 订单身份必须来自 mdp_std_so(MDP-only,不依赖任何源业务表)──────────────────
  103. SELECT (SELECT COUNT(*) FROM `dwd_product_design_kpi` p
  104. WHERE NOT EXISTS (
  105. SELECT 1 FROM `mdp_std_so` s
  106. WHERE s.`tenant_id` = p.`tenant_id` AND s.`order_id` = p.`sales_order_id`)) = 0;