在Python中使用executemany执行Oracle带返回值的INSERT语句遇阻求助
问题描述
早上好,我正尝试在Python中执行带返回值的INSERT INTO ... RETURNING SQL语句,希望使用executemany方法,但目前我的代码无法运行,恳请各位提供帮助,谢谢。
建表SQL
CREATE TABLE TABLE1 ( F1 NUMBER(*,0) GENERATED ALWAYS AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1, F2 NUMBER(*,0) NOT NULL ENABLE, CONSTRAINT "TABLE1_PK" PRIMARY KEY ("F1") )
我的Python代码
import cx_Oracle def makeCxDSNLessConnection(src): return cx_Oracle.connect(user=sUser, password=sPass ,dsn=src) def tempDoit(): oraCon = makeCxDSNLessConnection('EPAT') cur = oraCon.cursor() thislist=list() thisOut = cur.var(int) cur.execute("TRUNCATE TABLE TABLE1") for i in range(1000000): thislist.append((i,)) cur.executemany("INSERT INTO TABLE1(F2) VALUES(:1) RETURNING F1 INTO :2", thislist, thisOut ) oraCon.commit() while True: rows = cur.fetchmany(100) if not rows: break for row in rows: print(row)
解决方案
你的代码存在两个核心问题:
executemany绑定输出变量的方式错误:使用RETURNING子句配合executemany时,输出变量需要作为每个插入参数组的一部分传入,而非单独作为第三个参数。- 错误使用
fetchmany获取返回值:executemany执行带RETURNING的语句后,自增ID会直接存储在输出变量中,无需通过游标fetch方法获取。
修正后的完整代码
import cx_Oracle # 请替换为实际的数据库账号密码 sUser = "your_username" sPass = "your_password" def makeCxDSNLessConnection(src): return cx_Oracle.connect(user=sUser, password=sPass, dsn=src) def tempDoit(): oraCon = makeCxDSNLessConnection('EPAT') cur = oraCon.cursor() cur.execute("TRUNCATE TABLE TABLE1") total_records = 1000000 # 创建输出变量,指定数组大小匹配插入记录数 thisOut = cur.var(int, arraysize=total_records) # 构造包含输入参数和输出变量的参数列表 thislist = [(i, thisOut) for i in range(total_records)] # 执行批量插入 cur.executemany("INSERT INTO TABLE1(F2) VALUES(:1) RETURNING F1 INTO :2", thislist) oraCon.commit() # 从输出变量中提取所有返回的F1值 returned_ids = thisOut.getvalue() for f1_val in returned_ids: print(f1_val) cur.close() oraCon.close() tempDoit()
关键优化说明
- 输出变量数组大小:必须设置
arraysize为批量插入的记录数,确保能容纳所有返回的自增ID。 - 内存优化:如果插入百万级数据,直接构造超大列表会占用大量内存,建议分批次插入(比如每1万条一批),示例如下:
def tempDoit(): oraCon = makeCxDSNLessConnection('EPAT') cur = oraCon.cursor() cur.execute("TRUNCATE TABLE TABLE1") total_records = 1000000 batch_size = 10000 # 每次插入1万条,降低内存占用 for start in range(0, total_records, batch_size): end = min(start + batch_size, total_records) thisOut = cur.var(int, arraysize=batch_size) # 构造当前批次的参数列表 thislist = [(i, thisOut) for i in range(start, end)] cur.executemany("INSERT INTO TABLE1(F2) VALUES(:1) RETURNING F1 INTO :2", thislist) # 获取当前批次的返回ID returned_ids = thisOut.getvalue() for f1_val in returned_ids: if f1_val is not None: print(f1_val) oraCon.commit() cur.close() oraCon.close()
内容的提问来源于stack exchange,提问作者Z T Minhas
相关产品推荐
相关产品推荐

