python - 收到错误 cx_Oracle.DatabaseError : ORA-01008: not all variables bound while trying to bind the value of a list in a merge statement

标签 python sql oracle dataframe cx-oracle

过去几个小时我一直在绞尽脑汁,但无法找到根本原因。浏览了多篇文章但没有运气。

我正在尝试合并存储在 pandas 数据框中的值。 下面是我将数据帧转换为列表的代码

merchantinfo_lst = appenddata.values.tolist()

通过下面的代码,我尝试将数据合并到目标表中。

sql ='merge into bi.merchant_info_test ';
sql+=' using dual';
sql+='   on ( ATRANS_ID = :2 )';
sql+=' when matched then update set MERCHANT_INFO = :15, MESSAGE_PARAM = :16, PUBLISH_DATE = :13' ;  
sql+=' when not matched then insert( ADDRESS,ATRANS_ID,CITY_NAME,COUNTRY_CODE,LATITUDE,LONGITUDE,MERCHANT_CATEGORY_CODE,MERCHANT_DESCRIPTOR,MERCHANT_ID,';
sql+=' MERCHANT_NAME,PHONE_NUMBER,POSTAL_CODE,PUBLISH_DATE,STATE_PROVINCE_CODE,MERCHANT_INFO,MESSAGE_PARAM )'; 
sql+='  values( :1, :2, :3,:4,:5,:6,:7,:8,:9,:10,:11,:12,:13,:14,:15,:16 )';
for i in range(len(merchantinfo_lst)):
    cur.execute(sql,merchantinfo_lst[i])

我收到 cx_Oracle.DatabaseError: ORA-01008: 并非所有变量都绑定(bind),但所有值都存在于列表中,并且所有列都存在于目标表中。 无论我尝试什么,我都无法解决问题。

Python版本:2.7.5 cx_Oracle版本:7.3.0 目标数据库:Oracle Database 19c 企业版版本 19.0.0.0.0

表结构

    Name                   Null?    Type           
---------------------- -------- -------------- 
ATRANS_ID              NOT NULL RAW(36 BYTE)   
MERCHANT_ID                     VARCHAR2(20)   
MERCHANT_DESCRIPTOR             VARCHAR2(100)  
MERCHANT_NAME                   VARCHAR2(100)  
ADDRESS                         VARCHAR2(250)  
CITY_NAME                       VARCHAR2(100)  
STATE_PROVINCE_CODE             VARCHAR2(4)    
POSTAL_CODE                     VARCHAR2(10)   
COUNTRY_CODE                    VARCHAR2(10)   
LATITUDE                        VARCHAR2(20)   
LONGITUDE                       VARCHAR2(20)   
PHONE_NUMBER                    VARCHAR2(15)   
MERCHANT_CATEGORY_CODE          VARCHAR2(6)    
MERCHANT_INFO                   VARCHAR2(250)  
MESSAGE_PARAM                   VARCHAR2(2000) 
PUBLISH_DATE                    DATE

Python代码

def table_merge(data_frame,uname,passwd,oracle_dsn):
    merchantinfo = pd.DataFrame()
    transidinfo = pd.DataFrame()
    ora_con = oracle_conn(uname,passwd,oracle_dsn)
    cur = ora_con.cursor()
    now = datetime.now()
    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")    
    appenddata['MERCHANT_INFO'] = appenddata['MERCHANT_NAME']+ ' ' +appenddata['CITY_NAME']+ ' '+appenddata['STATE_PROVINCE_CODE']+ ' ' +appenddata['COUNTRY_CODE']+ ' ' +appenddata['POSTAL_CODE']
    appenddata['MESSAGE_PARAM'] = appenddata['MERCHANT_ID']+ '|' + appenddata['MERCHANT_INFO']
    appenddata['PUBLISH_DATE'] = dt_string
    merchantinfo_lst = appenddata.values.tolist()
    print('printing list')
    print(merchantinfo_lst)
    sql ='merge into bi.merchant_info_test ';
    sql+=' using dual';
    sql+='   on ( ATRANS_ID = :2 )';
    sql+=' when matched then update set MERCHANT_INFO = :15, MESSAGE_PARAM = :16, PUBLISH_DATE = :13' ;  
    sql+=' when not matched then insert( ADDRESS,ATRANS_ID,CITY_NAME,COUNTRY_CODE,LATITUDE,LONGITUDE,MERCHANT_CATEGORY_CODE,MERCHANT_DESCRIPTOR,MERCHANT_ID,';
    sql+=' MERCHANT_NAME,PHONE_NUMBER,POSTAL_CODE,PUBLISH_DATE,STATE_PROVINCE_CODE,MERCHANT_INFO,MESSAGE_PARAM )'; 
    sql+='  values( :1, :2, :3,:4,:5,:6,:7,:8,:9,:10,:11,:12,:13,:14,:15,:16 )';
    for i in range(len(merchantinfo_lst)):
        cur.execute(sql,merchantinfo_lst[i])
    cur.close()
    ora_con.commit()
    ora_con.close()

输出

    /home/kkant/microservice-poc % python consumer.py
printing list
[[u'dummy_address', u'123456789', u'dummy_city', u'91', u'', u'', u'2345', u'dummy', u'123', u'dummy_merchant', u'1234567890', u'123456', '27/05/2022 11:32:22', u'', u'dummy_merchant dummy_city  91 123456', u'123|dummy_merchant dummy_city  91 123456'], [u'dummy_address', u'1234567455', u'dummy_city', u'91', u'', u'', u'2345', u'dummy', u'456', u'dummy_merchant', u'1234567890', u'123456', '27/05/2022 11:32:22', u'', u'dummy_merchant dummy_city  91 123456', u'456|dummy_merchant dummy_city  91 123456']]
Traceback (most recent call last):
  File "consumer.py", line 102, in <module>
    table_merge(appenddata)       
  File "consumer.py", line 71, in table_merge
    cur.execute(sql,merchantinfo_lst[i])
cx_Oracle.DatabaseError: ORA-01008: not all variables bound

[enter image description here][1]

最佳答案

问题是您是按位置绑定(bind)的,而不是按名称绑定(bind)的。因此,每个绑定(bind)变量位置都需要一个条目。 SQL 语句第一部分中的值 :2 需要一个值,SQL 语句最后一部分中的值 :2 也需要一个值! (对于 SQL 语句中提到的每个绑定(bind)变量,依此类推 - 其中 20 个)。如果您不想这样做,您可以改为按名称绑定(bind)(并提供参数字典)。

另一种可行的方法是对所有参数执行“查询”,如下所示:

merge into bi.merchant_info_test target
using select :1 as x, :2, as y, :3 as z, ... from dual source
on target.atrans_id = source.atrans_id
when matched then update set merchant_info = source.merchant_info ...
when not matched then insert (ADDRESS, ...) values (source.address, ...)

这样一来,您就只有一个需要绑定(bind)变量的位置,而不是两个(对于其中一些)。

几天前发布的新 Python 驱动程序 (python-oracledb) 在使用精简模式时针对此类情况提供了更好的错误消息(有关更多详细信息,请参阅 documentation)。可能值得尝试使用该驱动程序的示例来找出问题的根源。

顺便说一句,插入多行时最好使用executemany(),而不是迭代列表并重复调用execute()。性能差异可能是惊人的,尤其是对于大量行!

关于python - 收到错误 cx_Oracle.DatabaseError : ORA-01008: not all variables bound while trying to bind the value of a list in a merge statement,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72408585/

相关文章:

javascript - Python - Flask - Google Charts API 获取每个 CategoryFilter 中的值并将其传递给 href

python - 如何在json文件中查找和替换值的一部分

python - 在 Python 版本之间切换?

sql - 计算属于特定类型的条目

python - 创建不锁定窗口的循环Pyqt4

sql - 检查所有表行是否相等

sql - 更新具有相同ID但行中不同数据的数据

java - 比较jpa中的时间戳列而不丢失微秒

.net - 检查oracle函数是否存在

php - Oracle/PHP - ORA-00911 更新字符无效