# -*- coding: utf-8 -*- # 票 03 D-13 存量回填:opportunity.owner_dept_id 恒空 → 按负责人(crm_auth_user.dept_id)回填 # 用法: # python backfill-owner-dept.py # 预检模式:只 SELECT,打印将影响的行 # python backfill-owner-dept.py --apply # 执行模式:真正 UPDATE import sys import pymysql DB = dict(host='8.129.84.155', port=3306, user='root', password='Itc@123456', database='crm', charset='utf8mb4') PRECHECK = """ SELECT o.id, o.opp_status, o.owner_user_id, o.owner_dept_id, u.dept_id AS user_dept_id FROM opportunity o JOIN crm_auth_user u ON u.id = o.owner_user_id WHERE o.owner_dept_id IS NULL AND o.owner_user_id IS NOT NULL AND o.deleted = 0 ORDER BY o.id """ ORPHANS = """ SELECT o.id, o.opp_status, o.owner_user_id, o.owner_dept_id FROM opportunity o WHERE o.owner_dept_id IS NULL AND o.owner_user_id IS NULL AND o.deleted = 0 ORDER BY o.id """ UPDATE = """ UPDATE opportunity o JOIN crm_auth_user u ON u.id = o.owner_user_id SET o.owner_dept_id = u.dept_id WHERE o.owner_dept_id IS NULL AND o.owner_user_id IS NOT NULL AND u.dept_id IS NOT NULL """ APPLY = '--apply' in sys.argv conn = pymysql.connect(**DB) try: with conn.cursor(pymysql.cursors.DictCursor) as cur: cur.execute(PRECHECK) rows = cur.fetchall() print('[precheck] backfillable rows =', len(rows)) for r in rows: print(' ', r) cur.execute(ORPHANS) orphans = cur.fetchall() print('[precheck] orphan rows (owner NULL, 不可回填) =', len(orphans)) for r in orphans: print(' ', r) if not APPLY: print('[dry-run] 未执行 UPDATE(加 --apply 执行)') sys.exit(0) cur.execute(UPDATE) affected = cur.rowcount conn.commit() print('[apply] UPDATE affected =', affected) # 回填后核验:存活行 owner_dept_id 残留 NULL 计数 cur.execute("SELECT COUNT(*) AS n FROM opportunity WHERE owner_dept_id IS NULL AND owner_user_id IS NOT NULL AND deleted = 0") print('[verify] 残留 NULL(有 owner)=', cur.fetchone()['n']) finally: conn.close()