fix: auto-verify验证引擎4项缺陷修复 verify-fix (OKR幂等防重累加/entity_id多租户回填/period期间过滤/status done->completed)
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
"""verify-engine-fix-20260830 DB 迁移脚本
|
||||
|
||||
1. kpi_values.entity_id 回填:kpi_id → kpi_definitions.entity_id(现有 67 条 NULL)
|
||||
2. action_plans.status 'done' → 'completed'(枚举修正;当前 0 条,防御性执行)
|
||||
|
||||
执行前先 SELECT 预览影响行数,再执行 UPDATE,最后回查验证。
|
||||
用法: venv/bin/python3 scripts/migrate_verify_fix_20260830.py
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from sqlalchemy import text
|
||||
from app.database import get_engine
|
||||
|
||||
|
||||
def main():
|
||||
engine = get_engine()
|
||||
with engine.connect() as conn:
|
||||
# ── 1. 预览 ──
|
||||
preview_null = conn.execute(text(
|
||||
"SELECT COUNT(*) AS cnt FROM kpi_values kv "
|
||||
"LEFT JOIN kpi_definitions kd ON kv.kpi_id = kd.id "
|
||||
"WHERE kv.entity_id IS NULL AND kd.entity_id IS NOT NULL"
|
||||
)).fetchone()
|
||||
preview_orphan = conn.execute(text(
|
||||
"SELECT COUNT(*) AS cnt FROM kpi_values kv "
|
||||
"LEFT JOIN kpi_definitions kd ON kv.kpi_id = kd.id "
|
||||
"WHERE kv.entity_id IS NULL AND kd.id IS NULL"
|
||||
)).fetchone()
|
||||
preview_done = conn.execute(text(
|
||||
"SELECT COUNT(*) AS cnt FROM action_plans WHERE status = 'done'"
|
||||
)).fetchone()
|
||||
|
||||
print(f"[预览] 可回填(entity_id NULL 且 kpi 存在): {preview_null.cnt}")
|
||||
print(f"[预览] 无法回填(kpi 不存在): {preview_orphan.cnt}")
|
||||
print(f"[预览] action_plans status='done': {preview_done.cnt}")
|
||||
|
||||
# ── 2. 执行回填 ──
|
||||
r = conn.execute(text(
|
||||
"UPDATE kpi_values kv "
|
||||
"JOIN kpi_definitions kd ON kv.kpi_id = kd.id "
|
||||
"SET kv.entity_id = kd.entity_id "
|
||||
"WHERE kv.entity_id IS NULL AND kd.entity_id IS NOT NULL"
|
||||
))
|
||||
print(f"[执行] kpi_values entity_id 回填 {r.rowcount} 条")
|
||||
|
||||
# 无法关联的孤儿行(kpi 不存在)→ 置默认 entity_id=1 并留 remark
|
||||
r2 = conn.execute(text(
|
||||
"UPDATE kpi_values kv "
|
||||
"LEFT JOIN kpi_definitions kd ON kv.kpi_id = kd.id "
|
||||
"SET kv.entity_id = 1, kv.remark = CONCAT(COALESCE(kv.remark, ''), '; verify-fix-20260830 孤儿行默认entity_id=1') "
|
||||
"WHERE kv.entity_id IS NULL AND kd.id IS NULL"
|
||||
))
|
||||
if r2.rowcount:
|
||||
print(f"[执行] 孤儿行置默认 entity_id=1: {r2.rowcount} 条")
|
||||
else:
|
||||
print("[执行] 无孤儿行需处理")
|
||||
|
||||
# ── 3. status done → completed ──
|
||||
r3 = conn.execute(text(
|
||||
"UPDATE action_plans SET status = 'completed' WHERE status = 'done'"
|
||||
))
|
||||
print(f"[执行] action_plans status done→completed: {r3.rowcount} 条")
|
||||
|
||||
conn.commit()
|
||||
|
||||
# ── 4. 验证 ──
|
||||
after_null = conn.execute(text(
|
||||
"SELECT COUNT(*) AS cnt FROM kpi_values WHERE entity_id IS NULL"
|
||||
)).fetchone()
|
||||
after_done = conn.execute(text(
|
||||
"SELECT COUNT(*) AS cnt FROM action_plans WHERE status = 'done'"
|
||||
)).fetchone()
|
||||
print(f"[验证] kpi_values entity_id IS NULL 残留: {after_null.cnt}(目标 0)")
|
||||
print(f"[验证] action_plans status='done' 残留: {after_done.cnt}(目标 0)")
|
||||
if after_null.cnt != 0:
|
||||
print("[结果] ❌ 回填不彻底,请人工检查")
|
||||
sys.exit(1)
|
||||
print("[结果] ✅ 迁移完成")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user