"""NAS 端:全量替换单张小表(DROP + CREATE + INSERT),幂等可重跑。 用于 constituent_unified / bs_adjust_factor 等小表。 - 纯 sqlite3 标准库,零第三方依赖(NAS 宿主 Python 3.8 也能跑)。 - DROP IF EXISTS + 权威 schema 重建 + INSERT:每次全量替换,重跑安全。 - 权威 schema(含主键/约束)硬编码在此,NAS 副本对齐 VPS。 用法: python merge_table.py --db /volume1/.../quant_trading.db --inc /tmp/t.db --table constituent_unified """ import argparse import sqlite3 # 权威 schema(对齐 VPS quant_trading.db)。新增表在此登记。 SCHEMAS = { "constituent_unified": ( "CREATE TABLE constituent_unified(" "index_code TEXT, code TEXT, code_name TEXT, source TEXT," "in_current INT, was_removed INT)" ), "bs_adjust_factor": ( "CREATE TABLE bs_adjust_factor(" "code TEXT NOT NULL, dividOperateDate TEXT NOT NULL," "foreAdjustFactor REAL, backAdjustFactor REAL, adjustFactor REAL," "PRIMARY KEY (code, dividOperateDate))" ), } # 列名(与源表对齐,用于 INSERT 列顺序)。 COLUMNS = { "constituent_unified": "index_code,code,code_name,source,in_current,was_removed", "bs_adjust_factor": "code,dividOperateDate,foreAdjustFactor,backAdjustFactor,adjustFactor", } # 额外索引(主键自带的不列)。 INDEXES = { "constituent_unified": [ "CREATE INDEX IF NOT EXISTS idx_cu_index ON constituent_unified(index_code)", "CREATE INDEX IF NOT EXISTS idx_cu_code ON constituent_unified(code)", ], "bs_adjust_factor": [], } def main(): ap = argparse.ArgumentParser(description="全量替换单张小表进 NAS 副本") ap.add_argument("--db", required=True, help="NAS quant_trading.db 路径") ap.add_argument("--inc", required=True, help="增量 sqlite 路径") ap.add_argument("--table", required=True, help="表名") args = ap.parse_args() tbl = args.table if tbl not in SCHEMAS: raise SystemExit("unknown table %s; add schema/columns first" % tbl) cols = COLUMNS[tbl] conn = sqlite3.connect(args.db) cur = conn.cursor() for p in ("PRAGMA journal_mode=WAL", "PRAGMA synchronous=NORMAL"): cur.execute(p) cur.execute("ATTACH DATABASE ? AS inc", (args.inc,)) inc_count = cur.execute( "SELECT COUNT(*) FROM inc.[%s]" % tbl).fetchone()[0] cur.execute("DROP TABLE IF EXISTS main.[%s]" % tbl) cur.execute(SCHEMAS[tbl]) for idx in INDEXES.get(tbl, []): cur.execute(idx) cur.execute( "INSERT INTO main.[%s](%s) SELECT %s FROM inc.[%s]" % (tbl, cols, cols, tbl) ) conn.commit() after = cur.execute( "SELECT COUNT(*) FROM main.[%s]" % tbl).fetchone()[0] conn.close() print("REPLACED table=%s inc=%d after=%d" % (tbl, inc_count, after)) if __name__ == "__main__": main()