#!/usr/bin/env python3 # -*- coding: utf-8 -*- """将 SQLite weekly_reports.db 的核心周报数据迁移到 MySQL resume 库。 仅迁移高质量核心数据(标准格式、含每日明细),默认同步全部,可按参数过滤。 用法: python3 migrate_to_mysql.py # 同步全部 SQLite 周报到 MySQL python3 migrate_to_mysql.py --dry-run # 只统计不写入 """ import os import sqlite3 import sys import pymysql BASE = "/home/yangxuan/.openclaw/workspace-resume/weekly-reports" SQLITE_DB = os.path.join(BASE, "weekly_reports.db") # MySQL 连接配置 MYSQL_HOST = "127.0.0.1" MYSQL_PORT = 3306 MYSQL_USER = "root" MYSQL_DB = "resume" def get_mysql_pwd(): """从 .env 读取 MySQL 密码""" env_path = "/home/yangxuan/.openclaw/.env" if os.path.exists(env_path): with open(env_path) as f: for line in f: line = line.strip() if line.startswith("MYSQL_PWD="): return line.split("=", 1)[1].strip() return os.environ.get("MYSQL_PWD", "") def main(): dry_run = "--dry-run" in sys.argv pwd = get_mysql_pwd() if not pwd: print("❌ 未找到 MySQL 密码(MYSQL_PWD),退出") return # 1. 读 SQLite conn = sqlite3.connect(SQLITE_DB) cur = conn.cursor() reports = cur.execute( "SELECT id, year, week_number, start_date, end_date, project, main_task, has_problems, file_path " "FROM weekly_reports ORDER BY year, week_number").fetchall() print(f"📂 SQLite 读取到 {len(reports)} 份周报") # 2. 连接 MySQL if dry_run: print("🔍 dry-run 模式:仅统计") for r in reports: print(f" W{r[2]:02d} ({r[0]}) {r[1]} | {r[5]} | {r[3]}~{r[4]}") conn.close() return my = pymysql.connect(host=MYSQL_HOST, port=MYSQL_PORT, user=MYSQL_USER, password=pwd, database=MYSQL_DB, charset="utf8mb4") myc = my.cursor() # 3. 逐份插入(UPSERT:先删同 year/week/project 再插,避免冲突) synced = 0 for (rid, year, wnum, start, end, project, main_task, has_prob, file_path) in reports: # 清掉同键旧数据 myc.execute( "DELETE FROM weekly_report_daily WHERE report_id IN " "(SELECT id FROM weekly_reports WHERE year=%s AND week_number=%s AND project=%s)", (year, wnum, project)) myc.execute( "DELETE FROM weekly_report_problems WHERE report_id IN " "(SELECT id FROM weekly_reports WHERE year=%s AND week_number=%s AND project=%s)", (year, wnum, project)) myc.execute( "DELETE FROM weekly_reports WHERE year=%s AND week_number=%s AND project=%s", (year, wnum, project)) # 插入主表 myc.execute( "INSERT INTO weekly_reports (year, week_number, start_date, end_date, project, main_task, has_problems, file_path) " "VALUES (%s,%s,%s,%s,%s,%s,%s,%s)", (year, wnum, start, end, project, main_task, 1 if has_prob else 0, file_path)) new_id = myc.lastrowid # 每日明细 daily = cur.execute( "SELECT day_of_week, work_date, work_items FROM weekly_report_daily WHERE report_id=? ORDER BY work_date", (rid,)).fetchall() for (dow, wd, items) in daily: myc.execute( "INSERT INTO weekly_report_daily (report_id, day_of_week, work_date, work_items) VALUES (%s,%s,%s,%s)", (new_id, dow, wd, items)) # 问题 probs = cur.execute( "SELECT problem_description FROM weekly_report_problems WHERE report_id=?", (rid,)).fetchall() for (p_desc,) in probs: myc.execute( "INSERT INTO weekly_report_problems (report_id, problem_description) VALUES (%s,%s)", (new_id, p_desc)) synced += 1 print(f" ✅ W{wnum:02d} ({project}) {start}~{end} | 明细{len(daily)}条 问题{len(probs)}条") my.commit() myc.close() my.close() conn.close() print(f"\n🎉 迁移完成:{synced} 份周报已写入 MySQL resume 库") if __name__ == "__main__": main()