You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python执行PL/SQL代码批量操作Oracle数据库无数据变更问题排查

Python执行PL/SQL代码批量操作Oracle数据库无数据变更问题排查

嗨Jegor,我来帮你一步步排查这个问题,从你贴的代码来看,有几个关键错误导致数据没有被正确插入/更新,咱们逐个梳理:

1. 致命的缩进错误(批量插入逻辑完全未执行)

看你Python代码里的批量处理部分,缩进明显错误:

if len(data) % batch_size == 0:
cursor.executemany(sql_insert, data)
    data = []

cursor.executemany这一行没有缩进,导致这个批量插入的逻辑永远不会触发!只有当最后剩余的data不为空时,才会执行一次插入操作;如果你的数据量刚好是batch_size的整数倍,最后data是空的,连这最后一次执行都不会触发,自然看不到任何数据变更。

2. 错误跳过第一行有效数据

你明确说明S3里的文件没有表头,但代码里却执行了:

headings = next(csv_reader)

这会直接跳过第一行有效数据,如果你测试的文件数据量很少,可能直接导致没有数据被处理。

3. PL/SQL的UPDATE语句缺少WHERE条件(逻辑错误)

你的PL/SQL代码里,UPDATE部分没有指定过滤条件:

Update %(oracle_table)s
Set STRING_COLUMN = :STRING_COLUMN;

这意味着只要counter>0(即表中存在任意一条ID匹配的记录),就会更新整个表的所有行的STRING_COLUMN,而不是当前要处理的那条ID对应的行!正确的写法必须加上WHERE条件:

Update %(oracle_table)s
Set STRING_COLUMN = :STRING_COLUMN
Where ID = :ID;

另外,用PL/SQL手动判断存在性其实不如Oracle原生的MERGE语句高效且安全,推荐直接替换成MERGE语句,避免手动逻辑的错误:

MERGE INTO %(oracle_table)s t
USING (SELECT :ID AS ID, :STRING_COLUMN AS STRING_COLUMN FROM DUAL) s
ON (t.ID = s.ID)
WHEN MATCHED THEN
  UPDATE SET t.STRING_COLUMN = s.STRING_COLUMN
WHEN NOT MATCHED THEN
  INSERT (ID, STRING_COLUMN) VALUES (s.ID, s.STRING_COLUMN)

这个语句能自动完成“存在则更新,不存在则插入”的逻辑,代码更简洁也更可靠。

4. 提交时机不完整

当前代码里,只有最后处理剩余数据时才调用connection.commit(),而前面每批次的executemany执行后都没有提交。虽然Oracle默认关闭自动提交,但最好每批次执行后都提交,避免事务过大导致性能问题或回滚风险。

修正后的完整代码示例

Python代码修正版

....
# SQL Statement
sql_insert = config.get('SQL_STATEMENT', 'sql_insert')

# Get File from S3 Bucket
obj = s3.Object(CDH_S3_Bucket, CDH_Path + '/' + s3_filename)
body = obj.get()['Body'].read().decode('utf-8').splitlines()

cursor.setinputsizes(None, 25)

batch_size = 10000
data = []  # 初始化data列表,避免未定义报错

# ----------------------------------------------------------
print("Import Data...")
print("------------------------------")
csv_reader = csv.reader(body, delimiter=',')
# 没有表头,注释掉跳过行的代码
# headings = next(csv_reader)

for line in csv_reader:
    data.append(line)
    if len(data) % batch_size == 0:
        cursor.executemany(sql_insert, data)
        connection.commit()  # 每批次执行后提交
        data = []

if data:
    cursor.executemany(sql_insert, data)
    connection.commit()
#------------------------------------------------------------
# Close Cursor and Connection
cursor.close()
connection.close()
....

.ini文件修正版(使用MERGE替代PL/SQL)

[SQL_STATEMENT]
oracle_table = TEST_TABLE
sql_insert = """
MERGE INTO %(oracle_table)s t
USING (SELECT :ID AS ID, :STRING_COLUMN AS STRING_COLUMN FROM DUAL) s
ON (t.ID = s.ID)
WHEN MATCHED THEN
  UPDATE SET t.STRING_COLUMN = s.STRING_COLUMN
WHEN NOT MATCHED THEN
  INSERT (ID, STRING_COLUMN) VALUES (s.ID, s.STRING_COLUMN)
"""

如果你坚持使用原来的PL/SQL逻辑,记得修正UPDATE的WHERE条件:

[SQL_STATEMENT]
oracle_table = TEST_TABLE
sql_insert = """Declare
       counter number;
    Begin
       Select
          Count(*) into counter
       From %(oracle_table)s
       Where ID  = :ID;

       If counter = 0 Then
          insert into %(oracle_table)s (ID,STRING_COLUMN) 
          values (:ID,:STRING_COLUMN);
       Else
          Update %(oracle_table)s
          Set STRING_COLUMN = :STRING_COLUMN
          Where ID = :ID;  -- 新增WHERE条件
       End If;
    End;"""

备注:内容来源于stack exchange,提问作者Jegor Wieler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 17:39:28