ORA-01008: 在 Python 中执行合并语句时,并非所有变量都绑定
ORA-01008: not all variables bound when executing merge statement in Python
我目前正在尝试将 SFTP 位置的文件中的数据提取到它们各自的 Oracle table 中。我使用 cx_oracle 库来创建必要的连接并执行查询。在这个用例中,我试图通过使用 DUAL 运行 MERGE 语句到 table 中。
for i, row in dataset.iterrows():
merge_sql = "MERGE INTO schema.{} USING DUAL ON ( SOURCE_SYSTEM_ID = :1 ) " \
"WHEN MATCHED THEN UPDATE SET {} " \
"WHEN NOT MATCHED THEN INSERT({}) VALUES({})".format(self.source_table_name,
set_stmt_sql_list_as_str,
col_names_as_str,
col_list_from_df_as_str)
oracle_cursor.execute(merge_sql, tuple(row))
在上面的代码片段中,dataset 是从 SFTP 位置读取文件后创建的数据帧。
替换值后 merge_sql 字符串如下所示:
MERGE INTO schema.table USING DUAL ON ( SOURCE_SYSTEM_ID = :1 )
WHEN MATCHED THEN UPDATE SET FILE_ID_2=:0,SOURCE_SYSTEM_ID=:1,ACCOUNT_NUMBER_PART1=:2,ACCOUNT_NUMBER_PART2=:3,CONTACT_TYPE=:4,CDM_ACTION_CODE=:5,ACCOUNT_HOLDER_NAME=:6,CREDIT_CARD_TYPE=:7,CARD_HOLDER_NAME=:8,CC_TOKEN=:9,CREDIT_CARD_MASKED=:10,CREDIT_CARD_EXPIRY=:11,BP_ROLE=:12,BP_ROLE_END_DATE=:13,CUST_CREDIT_STATUS=:14,BLOCKED_REASON=:15,CREDIT_LIMIT=:16,ANALYST_OR_COLLECTOR_COD=:17,CREDIT_REVIEW_DATE=:18,STOP_ORDER_ENTRY=:19,EMAIL_ADDRESS=:20,CITY_NAME=:21,COUNTRY_CODE=:22,FAX_NUMBER=:23,PO_BOX=:24,CITY_POSTAL_CODE=:25,STATE_CODE=:26,ADDRESS_LINE_2=:27,ADDRESS_LINE_1=:28,TELEPHONE_NUMBER=:29,LAST_NAME=:30,FIRST_NAME=:31,CONTACT_PERSON_FUNC=:32,NOTES=:33,SALUTATION=:34,VALID_FROM=:35,VALID_TO=:36,BUSINESS_PARTNER_REL=:37,RECONCILIATION_ACCNT=:38,CUST_SERV_CONT_SALUT=:39,STATEMENT_CODE=:40,TERMS_CODE=:41,DUNNING_LEVEL=:42,DUNNING_BLOCK=:43,CURRENT_DUNNING_LVL=:44,UC_FLAG=:45,CUSTOMER_CITY=:46,CUSTOMER_COUNTRY_COD=:47,CUSTOMER_FAX_NUM=:48,CUSTOMER_PO_BOX=:49,CUSTOMER_ZIP_CODE=:50,CUSTOMER_STATE=:51,CUSTOMER_ADDR_LINE_2=:52,CUSTOMER_ADDR_LINE_1=:53,COMPANY_NAME=:54,VALIDITY_START_DATE=:55,VALIDITY_END_DATE=:56,VALIDEND_BP_ROLE_DATE=:57,EXTERNAL_ACCT_NUMBER=:58,SOURCE_SYSTEM_NAME=:59,PROCESS_FLAG=:60,FILE_NM=:61,FILE_LOAD_DATE=:62,IND_ORG_FLAG=:63,LEGACY_ID=:64
WHEN NOT MATCHED THEN INSERT(FILE_ID_2,SOURCE_SYSTEM_ID,ACCOUNT_NUMBER_PART1,ACCOUNT_NUMBER_PART2,CONTACT_TYPE,CDM_ACTION_CODE,ACCOUNT_HOLDER_NAME,CREDIT_CARD_TYPE,CARD_HOLDER_NAME,CC_TOKEN,CREDIT_CARD_MASKED,CREDIT_CARD_EXPIRY,BP_ROLE,BP_ROLE_END_DATE,CUST_CREDIT_STATUS,BLOCKED_REASON,CREDIT_LIMIT,ANALYST_OR_COLLECTOR_COD,CREDIT_REVIEW_DATE,STOP_ORDER_ENTRY,EMAIL_ADDRESS,CITY_NAME,COUNTRY_CODE,FAX_NUMBER,PO_BOX,CITY_POSTAL_CODE,STATE_CODE,ADDRESS_LINE_2,ADDRESS_LINE_1,TELEPHONE_NUMBER,LAST_NAME,FIRST_NAME,CONTACT_PERSON_FUNC,NOTES,SALUTATION,VALID_FROM,VALID_TO,BUSINESS_PARTNER_REL,RECONCILIATION_ACCNT,CUST_SERV_CONT_SALUT,STATEMENT_CODE,TERMS_CODE,DUNNING_LEVEL,DUNNING_BLOCK,CURRENT_DUNNING_LVL,UC_FLAG,CUSTOMER_CITY,CUSTOMER_COUNTRY_COD,CUSTOMER_FAX_NUM,CUSTOMER_PO_BOX,CUSTOMER_ZIP_CODE,CUSTOMER_STATE,CUSTOMER_ADDR_LINE_2,CUSTOMER_ADDR_LINE_1,COMPANY_NAME,VALIDITY_START_DATE,VALIDITY_END_DATE,VALIDEND_BP_ROLE_DATE,EXTERNAL_ACCT_NUMBER,SOURCE_SYSTEM_NAME,PROCESS_FLAG,FILE_NM,FILE_LOAD_DATE,IND_ORG_FLAG,LEGACY_ID)
VALUES(:0,:1,:2,:3,:4,:5,:6,:7,:8,:9,:10,:11,:12,:13,:14,:15,:16,:17,:18,:19,:20,:21,:22,:23,:24,:25,:26,:27,:28,:29,:30,:31,:32,:33,:34,:35,:36,:37,:38,:39,:40,:41,:42,:43,:44,:45,:46,:47,:48,:49,:50,:51,:52,:53,:54,:55,:56,:57,:58,:59,:60,:61,:62,:63,:64)
当我尝试执行上述 SQL 时,出现以下错误
ORA-01008: not all variables bound
当我尝试使用相同的方法进行如下所示的简单 INSERT 时,效果非常好:
sql = "INSERT INTO PWC_ADMIN.{}({}) VALUES({})" \
.format(self.source_table_name, col_names_as_str, col_list_from_df_as_str)
包括我正在尝试合并的table的DDL供参考:
CREATE TABLE "schema"."table"
( "FILE_ID_2" VARCHAR2(3 CHAR),
"SOURCE_SYSTEM_ID" VARCHAR2(30 CHAR),
"ACCOUNT_NUMBER_PART1" VARCHAR2(7 CHAR),
"ACCOUNT_NUMBER_PART2" VARCHAR2(4 CHAR),
"CONTACT_TYPE" VARCHAR2(4 CHAR),
"CDM_ACTION_CODE" VARCHAR2(3 CHAR),
"ACCOUNT_HOLDER_NAME" VARCHAR2(100 CHAR),
"CREDIT_CARD_TYPE" VARCHAR2(2 CHAR),
"CARD_HOLDER_NAME" VARCHAR2(50),
"CC_TOKEN" VARCHAR2(24 CHAR),
"CREDIT_CARD_MASKED" VARCHAR2(19 CHAR),
"CREDIT_CARD_EXPIRY" VARCHAR2(4 CHAR),
"BP_ROLE" VARCHAR2(6 CHAR),
"BP_ROLE_END_DATE" VARCHAR2(8 CHAR),
"CUST_CREDIT_STATUS" CHAR(1),
"BLOCKED_REASON" VARCHAR2(25 CHAR),
"CREDIT_LIMIT" NUMBER(11,2),
"ANALYST_OR_COLLECTOR_COD" VARCHAR2(4 CHAR),
"CREDIT_REVIEW_DATE" NUMBER(7,0),
"STOP_ORDER_ENTRY" CHAR(1),
"EMAIL_ADDRESS" VARCHAR2(50 CHAR),
"CITY_NAME" VARCHAR2(24 CHAR),
"COUNTRY_CODE" VARCHAR2(4 CHAR),
"FAX_NUMBER" VARCHAR2(15 CHAR),
"PO_BOX" VARCHAR2(25 CHAR),
"CITY_POSTAL_CODE" VARCHAR2(9 CHAR),
"STATE_CODE" VARCHAR2(2 CHAR),
"ADDRESS_LINE_2" VARCHAR2(50 CHAR),
"ADDRESS_LINE_1" VARCHAR2(50 CHAR),
"TELEPHONE_NUMBER" VARCHAR2(15 CHAR),
"LAST_NAME" VARCHAR2(30 CHAR),
"FIRST_NAME" VARCHAR2(20 CHAR),
"CONTACT_PERSON_FUNC" VARCHAR2(2 CHAR),
"NOTES" VARCHAR2(60 CHAR),
"SALUTATION" VARCHAR2(2 CHAR),
"VALID_FROM" VARCHAR2(8 CHAR),
"VALID_TO" VARCHAR2(8 CHAR),
"BUSINESS_PARTNER_REL" VARCHAR2(6 CHAR),
"RECONCILIATION_ACCNT" VARCHAR2(8 CHAR),
"CUST_SERV_CONT_SALUT" CHAR(1),
"STATEMENT_CODE" CHAR(1),
"TERMS_CODE" VARCHAR2(2 CHAR),
"DUNNING_LEVEL" CHAR(1),
"DUNNING_BLOCK" CHAR(1),
"CURRENT_DUNNING_LVL" CHAR(1),
"UC_FLAG" CHAR(1),
"CUSTOMER_CITY" VARCHAR2(24 CHAR),
"CUSTOMER_COUNTRY_COD" VARCHAR2(4 CHAR),
"CUSTOMER_FAX_NUM" VARCHAR2(15 CHAR),
"CUSTOMER_PO_BOX" VARCHAR2(25 CHAR),
"CUSTOMER_ZIP_CODE" VARCHAR2(9 CHAR),
"CUSTOMER_STATE" VARCHAR2(2 CHAR),
"CUSTOMER_ADDR_LINE_2" VARCHAR2(30 CHAR),
"CUSTOMER_ADDR_LINE_1" VARCHAR2(30 CHAR),
"COMPANY_NAME" VARCHAR2(50 CHAR),
"VALIDITY_START_DATE" VARCHAR2(8 CHAR),
"VALIDITY_END_DATE" VARCHAR2(8 CHAR),
"VALIDEND_BP_ROLE_DATE" VARCHAR2(8 CHAR),
"EXTERNAL_ACCT_NUMBER" VARCHAR2(25 CHAR),
"SOURCE_SYSTEM_NAME" VARCHAR2(10 CHAR),
"PROCESS_FLAG" CHAR(1),
"FILE_NM" VARCHAR2(256 CHAR),
"FILE_LOAD_DATE" DATE,
"IND_ORG_FLAG" CHAR(1),
"LEGACY_ID" VARCHAR2(25 CHAR)
);
我已经尝试在 SO 和其他地方寻找原因,并尝试调试我是否遗漏了我在 SQL 中替换的那些列表中的任何内容,我无法成功。有没有人遇到过这类问题?如果有任何帮助,我们将不胜感激。
如果您只绑定一次变量,会更容易和更易读,如下所示:
for i, row in dataset.iterrows():
merge_sql = "MERGE INTO schema.{} dst " \
"USING (SELECT {} DUAL) src " \
"ON ( dst.SOURCE_SYSTEM_ID = src.SOURCE_SYSTEM_ID ) " \
"WHEN MATCHED THEN UPDATE SET {} " \
"WHEN NOT MATCHED THEN INSERT({}) VALUES({})".format(self.source_table_name,
using_stmt_sql_list_as_str,
set_stmt_sql_list_as_str,
col_names_as_str,
col_names_as_str)
oracle_cursor.execute(merge_sql, tuple(row))
其中 using_stmt_sql_list_as_str
是
:0 as FILE_ID_2
:1 as SOURCE_SYSTEM_ID
:2 as ACCOUNT_NUMBER_PART1
:3 as ACCOUNT_NUMBER_PART2
:4 as CONTACT_TYPE
:5 as CDM_ACTION_CODE
:6 as ACCOUNT_HOLDER_NAME
:7 as CREDIT_CARD_TYPE
:8 as CARD_HOLDER_NAME
:9 as CC_TOKEN
:10 as CREDIT_CARD_MASKED
:11 as CREDIT_CARD_EXPIRY
:12 as BP_ROLE
:13 as BP_ROLE_END_DATE
:14 as CUST_CREDIT_STATUS
:15 as BLOCKED_REASON
:16 as CREDIT_LIMIT
:17 as ANALYST_OR_COLLECTOR_COD
:18 as CREDIT_REVIEW_DATE
:19 as STOP_ORDER_ENTRY
:20 as EMAIL_ADDRESS
:21 as CITY_NAME
:22 as COUNTRY_CODE
:23 as FAX_NUMBER
:24 as PO_BOX
:25 as CITY_POSTAL_CODE
:26 as STATE_CODE
:27 as ADDRESS_LINE_2
:28 as ADDRESS_LINE_1
:29 as TELEPHONE_NUMBER
:30 as LAST_NAME
:31 as FIRST_NAME
:32 as CONTACT_PERSON_FUNC
:33 as NOTES
:34 as SALUTATION
:35 as VALID_FROM
:36 as VALID_TO
:37 as BUSINESS_PARTNER_REL
:38 as RECONCILIATION_ACCNT
:39 as CUST_SERV_CONT_SALUT
:40 as STATEMENT_CODE
:41 as TERMS_CODE
:42 as DUNNING_LEVEL
:43 as DUNNING_BLOCK
:44 as CURRENT_DUNNING_LVL
:45 as UC_FLAG
:46 as CUSTOMER_CITY
:47 as CUSTOMER_COUNTRY_COD
:48 as CUSTOMER_FAX_NUM
:49 as CUSTOMER_PO_BOX
:50 as CUSTOMER_ZIP_CODE
:51 as CUSTOMER_STATE
:52 as CUSTOMER_ADDR_LINE_2
:53 as CUSTOMER_ADDR_LINE_1
:54 as COMPANY_NAME
:55 as VALIDITY_START_DATE
:56 as VALIDITY_END_DATE
:57 as VALIDEND_BP_ROLE_DATE
:58 as EXTERNAL_ACCT_NUMBER
:59 as SOURCE_SYSTEM_NAME
:60 as PROCESS_FLAG
:61 as FILE_NM
:62 as FILE_LOAD_DATE
:63 as IND_ORG_FLAG
:64 as LEGACY_ID
和set_stmt_sql_list_as_str
:
dst.FILE_ID_2=src.FILE_ID_2,
dst.ACCOUNT_NUMBER_PART1=src.ACCOUNT_NUMBER_PART1,
dst.ACCOUNT_NUMBER_PART2=src.ACCOUNT_NUMBER_PART2,
dst.CONTACT_TYPE=src.CONTACT_TYPE,
dst.CDM_ACTION_CODE=src.CDM_ACTION_CODE,
dst.ACCOUNT_HOLDER_NAME=src.ACCOUNT_HOLDER_NAME,
dst.CREDIT_CARD_TYPE=src.CREDIT_CARD_TYPE,
dst.CARD_HOLDER_NAME=src.CARD_HOLDER_NAME,
dst.CC_TOKEN=src.CC_TOKEN,
dst.CREDIT_CARD_MASKED=src.CREDIT_CARD_MASKED,
dst.CREDIT_CARD_EXPIRY=src.CREDIT_CARD_EXPIRY,
dst.BP_ROLE=src.BP_ROLE,
dst.BP_ROLE_END_DATE=src.BP_ROLE_END_DATE,
dst.CUST_CREDIT_STATUS=src.CUST_CREDIT_STATUS,
dst.BLOCKED_REASON=src.BLOCKED_REASON,
dst.CREDIT_LIMIT=src.CREDIT_LIMIT,
dst.ANALYST_OR_COLLECTOR_COD=src.ANALYST_OR_COLLECTOR_COD,
dst.CREDIT_REVIEW_DATE=src.CREDIT_REVIEW_DATE,
dst.STOP_ORDER_ENTRY=src.STOP_ORDER_ENTRY,
dst.EMAIL_ADDRESS=src.EMAIL_ADDRESS,
dst.CITY_NAME=src.CITY_NAME,
dst.COUNTRY_CODE=src.COUNTRY_CODE,
dst.FAX_NUMBER=src.FAX_NUMBER,
dst.PO_BOX=src.PO_BOX,
dst.CITY_POSTAL_CODE=src.CITY_POSTAL_CODE,
dst.STATE_CODE=src.STATE_CODE,
dst.ADDRESS_LINE_2=src.ADDRESS_LINE_2,
dst.ADDRESS_LINE_1=src.ADDRESS_LINE_1,
dst.TELEPHONE_NUMBER=src.TELEPHONE_NUMBER,
dst.LAST_NAME=src.LAST_NAME,
dst.FIRST_NAME=src.FIRST_NAME,
dst.CONTACT_PERSON_FUNC=src.CONTACT_PERSON_FUNC,
dst.NOTES=src.NOTES,
dst.SALUTATION=src.SALUTATION,
dst.VALID_FROM=src.VALID_FROM,
dst.VALID_TO=src.VALID_TO,
dst.BUSINESS_PARTNER_REL=src.BUSINESS_PARTNER_REL,
dst.RECONCILIATION_ACCNT=src.RECONCILIATION_ACCNT,
dst.CUST_SERV_CONT_SALUT=src.CUST_SERV_CONT_SALUT,
dst.STATEMENT_CODE=src.STATEMENT_CODE,
dst.TERMS_CODE=src.TERMS_CODE,
dst.DUNNING_LEVEL=src.DUNNING_LEVEL,
dst.DUNNING_BLOCK=src.DUNNING_BLOCK,
dst.CURRENT_DUNNING_LVL=src.CURRENT_DUNNING_LVL,
dst.UC_FLAG=src.UC_FLAG,
dst.CUSTOMER_CITY=src.CUSTOMER_CITY,
dst.CUSTOMER_COUNTRY_COD=src.CUSTOMER_COUNTRY_COD,
dst.CUSTOMER_FAX_NUM=src.CUSTOMER_FAX_NUM,
dst.CUSTOMER_PO_BOX=src.CUSTOMER_PO_BOX,
dst.CUSTOMER_ZIP_CODE=src.CUSTOMER_ZIP_CODE,
dst.CUSTOMER_STATE=src.CUSTOMER_STATE,
dst.CUSTOMER_ADDR_LINE_2=src.CUSTOMER_ADDR_LINE_2,
dst.CUSTOMER_ADDR_LINE_1=src.CUSTOMER_ADDR_LINE_1,
dst.COMPANY_NAME=src.COMPANY_NAME,
dst.VALIDITY_START_DATE=src.VALIDITY_START_DATE,
dst.VALIDITY_END_DATE=src.VALIDITY_END_DATE,
dst.VALIDEND_BP_ROLE_DATE=src.VALIDEND_BP_ROLE_DATE,
dst.EXTERNAL_ACCT_NUMBER=src.EXTERNAL_ACCT_NUMBER,
dst.SOURCE_SYSTEM_NAME=src.SOURCE_SYSTEM_NAME,
dst.PROCESS_FLAG=src.PROCESS_FLAG,
dst.FILE_NM=src.FILE_NM,
dst.FILE_LOAD_DATE=src.FILE_LOAD_DATE,
dst.IND_ORG_FLAG=src.IND_ORG_FLAG,
dst.LEGACY_ID=src.LEGACY_ID
即,您需要跳过 dst.SOURCE_SYSTEM_ID=src.SOURCE_SYSTEM_ID,
,因为您无法更改用于 ON(...)
匹配条件的列。
因此您的最终合并语句如下所示:
MERGE INTO schema.table dst
USING ( select
:0 as FILE_ID_2,
:1 as SOURCE_SYSTEM_ID,
:2 as ACCOUNT_NUMBER_PART1,
:3 as ACCOUNT_NUMBER_PART2,
:4 as CONTACT_TYPE,
...
from DUAL) src
ON ( dst.SOURCE_SYSTEM_ID = src.SOURCE_SYSTEM_ID )
WHEN MATCHED THEN UPDATE SET
dst.FILE_ID_2=src.FILE_ID_2,
dst.ACCOUNT_NUMBER_PART1=src.ACCOUNT_NUMBER_PART1,
dst.ACCOUNT_NUMBER_PART2=src.ACCOUNT_NUMBER_PART2,
...
WHEN NOT MATCHED THEN INSERT(FILE_ID_2,SOURCE_SYSTEM_ID,ACCOUNT_NUMBER_PART1,ACCOUNT_NUMBER_PART2,CONTACT_TYPE,CDM_ACTION_CODE,ACCOUNT_HOLDER_NAME,CREDIT_CARD_TYPE,CARD_HOLDER_NAME,CC_TOKEN,CREDIT_CARD_MASKED,CREDIT_CARD_EXPIRY,BP_ROLE,BP_ROLE_END_DATE,CUST_CREDIT_STATUS,BLOCKED_REASON,CREDIT_LIMIT,ANALYST_OR_COLLECTOR_COD,CREDIT_REVIEW_DATE,STOP_ORDER_ENTRY,EMAIL_ADDRESS,CITY_NAME,COUNTRY_CODE,FAX_NUMBER,PO_BOX,CITY_POSTAL_CODE,STATE_CODE,ADDRESS_LINE_2,ADDRESS_LINE_1,TELEPHONE_NUMBER,LAST_NAME,FIRST_NAME,CONTACT_PERSON_FUNC,NOTES,SALUTATION,VALID_FROM,VALID_TO,BUSINESS_PARTNER_REL,RECONCILIATION_ACCNT,CUST_SERV_CONT_SALUT,STATEMENT_CODE,TERMS_CODE,DUNNING_LEVEL,DUNNING_BLOCK,CURRENT_DUNNING_LVL,UC_FLAG,CUSTOMER_CITY,CUSTOMER_COUNTRY_COD,CUSTOMER_FAX_NUM,CUSTOMER_PO_BOX,CUSTOMER_ZIP_CODE,CUSTOMER_STATE,CUSTOMER_ADDR_LINE_2,CUSTOMER_ADDR_LINE_1,COMPANY_NAME,VALIDITY_START_DATE,VALIDITY_END_DATE,VALIDEND_BP_ROLE_DATE,EXTERNAL_ACCT_NUMBER,SOURCE_SYSTEM_NAME,PROCESS_FLAG,FILE_NM,FILE_LOAD_DATE,IND_ORG_FLAG,LEGACY_ID)
VALUES(FILE_ID_2,SOURCE_SYSTEM_ID,ACCOUNT_NUMBER_PART1,ACCOUNT_NUMBER_PART2,CONTACT_TYPE,CDM_ACTION_CODE,ACCOUNT_HOLDER_NAME,CREDIT_CARD_TYPE,CARD_HOLDER_NAME,CC_TOKEN,CREDIT_CARD_MASKED,CREDIT_CARD_EXPIRY,BP_ROLE,BP_ROLE_END_DATE,CUST_CREDIT_STATUS,BLOCKED_REASON,CREDIT_LIMIT,ANALYST_OR_COLLECTOR_COD,CREDIT_REVIEW_DATE,STOP_ORDER_ENTRY,EMAIL_ADDRESS,CITY_NAME,COUNTRY_CODE,FAX_NUMBER,PO_BOX,CITY_POSTAL_CODE,STATE_CODE,ADDRESS_LINE_2,ADDRESS_LINE_1,TELEPHONE_NUMBER,LAST_NAME,FIRST_NAME,CONTACT_PERSON_FUNC,NOTES,SALUTATION,VALID_FROM,VALID_TO,BUSINESS_PARTNER_REL,RECONCILIATION_ACCNT,CUST_SERV_CONT_SALUT,STATEMENT_CODE,TERMS_CODE,DUNNING_LEVEL,DUNNING_BLOCK,CURRENT_DUNNING_LVL,UC_FLAG,CUSTOMER_CITY,CUSTOMER_COUNTRY_COD,CUSTOMER_FAX_NUM,CUSTOMER_PO_BOX,CUSTOMER_ZIP_CODE,CUSTOMER_STATE,CUSTOMER_ADDR_LINE_2,CUSTOMER_ADDR_LINE_1,COMPANY_NAME,VALIDITY_START_DATE,VALIDITY_END_DATE,VALIDEND_BP_ROLE_DATE,EXTERNAL_ACCT_NUMBER,SOURCE_SYSTEM_NAME,PROCESS_FLAG,FILE_NM,FILE_LOAD_DATE,IND_ORG_FLAG,LEGACY_ID)
我目前正在尝试将 SFTP 位置的文件中的数据提取到它们各自的 Oracle table 中。我使用 cx_oracle 库来创建必要的连接并执行查询。在这个用例中,我试图通过使用 DUAL 运行 MERGE 语句到 table 中。
for i, row in dataset.iterrows():
merge_sql = "MERGE INTO schema.{} USING DUAL ON ( SOURCE_SYSTEM_ID = :1 ) " \
"WHEN MATCHED THEN UPDATE SET {} " \
"WHEN NOT MATCHED THEN INSERT({}) VALUES({})".format(self.source_table_name,
set_stmt_sql_list_as_str,
col_names_as_str,
col_list_from_df_as_str)
oracle_cursor.execute(merge_sql, tuple(row))
在上面的代码片段中,dataset 是从 SFTP 位置读取文件后创建的数据帧。
替换值后 merge_sql 字符串如下所示:
MERGE INTO schema.table USING DUAL ON ( SOURCE_SYSTEM_ID = :1 )
WHEN MATCHED THEN UPDATE SET FILE_ID_2=:0,SOURCE_SYSTEM_ID=:1,ACCOUNT_NUMBER_PART1=:2,ACCOUNT_NUMBER_PART2=:3,CONTACT_TYPE=:4,CDM_ACTION_CODE=:5,ACCOUNT_HOLDER_NAME=:6,CREDIT_CARD_TYPE=:7,CARD_HOLDER_NAME=:8,CC_TOKEN=:9,CREDIT_CARD_MASKED=:10,CREDIT_CARD_EXPIRY=:11,BP_ROLE=:12,BP_ROLE_END_DATE=:13,CUST_CREDIT_STATUS=:14,BLOCKED_REASON=:15,CREDIT_LIMIT=:16,ANALYST_OR_COLLECTOR_COD=:17,CREDIT_REVIEW_DATE=:18,STOP_ORDER_ENTRY=:19,EMAIL_ADDRESS=:20,CITY_NAME=:21,COUNTRY_CODE=:22,FAX_NUMBER=:23,PO_BOX=:24,CITY_POSTAL_CODE=:25,STATE_CODE=:26,ADDRESS_LINE_2=:27,ADDRESS_LINE_1=:28,TELEPHONE_NUMBER=:29,LAST_NAME=:30,FIRST_NAME=:31,CONTACT_PERSON_FUNC=:32,NOTES=:33,SALUTATION=:34,VALID_FROM=:35,VALID_TO=:36,BUSINESS_PARTNER_REL=:37,RECONCILIATION_ACCNT=:38,CUST_SERV_CONT_SALUT=:39,STATEMENT_CODE=:40,TERMS_CODE=:41,DUNNING_LEVEL=:42,DUNNING_BLOCK=:43,CURRENT_DUNNING_LVL=:44,UC_FLAG=:45,CUSTOMER_CITY=:46,CUSTOMER_COUNTRY_COD=:47,CUSTOMER_FAX_NUM=:48,CUSTOMER_PO_BOX=:49,CUSTOMER_ZIP_CODE=:50,CUSTOMER_STATE=:51,CUSTOMER_ADDR_LINE_2=:52,CUSTOMER_ADDR_LINE_1=:53,COMPANY_NAME=:54,VALIDITY_START_DATE=:55,VALIDITY_END_DATE=:56,VALIDEND_BP_ROLE_DATE=:57,EXTERNAL_ACCT_NUMBER=:58,SOURCE_SYSTEM_NAME=:59,PROCESS_FLAG=:60,FILE_NM=:61,FILE_LOAD_DATE=:62,IND_ORG_FLAG=:63,LEGACY_ID=:64
WHEN NOT MATCHED THEN INSERT(FILE_ID_2,SOURCE_SYSTEM_ID,ACCOUNT_NUMBER_PART1,ACCOUNT_NUMBER_PART2,CONTACT_TYPE,CDM_ACTION_CODE,ACCOUNT_HOLDER_NAME,CREDIT_CARD_TYPE,CARD_HOLDER_NAME,CC_TOKEN,CREDIT_CARD_MASKED,CREDIT_CARD_EXPIRY,BP_ROLE,BP_ROLE_END_DATE,CUST_CREDIT_STATUS,BLOCKED_REASON,CREDIT_LIMIT,ANALYST_OR_COLLECTOR_COD,CREDIT_REVIEW_DATE,STOP_ORDER_ENTRY,EMAIL_ADDRESS,CITY_NAME,COUNTRY_CODE,FAX_NUMBER,PO_BOX,CITY_POSTAL_CODE,STATE_CODE,ADDRESS_LINE_2,ADDRESS_LINE_1,TELEPHONE_NUMBER,LAST_NAME,FIRST_NAME,CONTACT_PERSON_FUNC,NOTES,SALUTATION,VALID_FROM,VALID_TO,BUSINESS_PARTNER_REL,RECONCILIATION_ACCNT,CUST_SERV_CONT_SALUT,STATEMENT_CODE,TERMS_CODE,DUNNING_LEVEL,DUNNING_BLOCK,CURRENT_DUNNING_LVL,UC_FLAG,CUSTOMER_CITY,CUSTOMER_COUNTRY_COD,CUSTOMER_FAX_NUM,CUSTOMER_PO_BOX,CUSTOMER_ZIP_CODE,CUSTOMER_STATE,CUSTOMER_ADDR_LINE_2,CUSTOMER_ADDR_LINE_1,COMPANY_NAME,VALIDITY_START_DATE,VALIDITY_END_DATE,VALIDEND_BP_ROLE_DATE,EXTERNAL_ACCT_NUMBER,SOURCE_SYSTEM_NAME,PROCESS_FLAG,FILE_NM,FILE_LOAD_DATE,IND_ORG_FLAG,LEGACY_ID)
VALUES(:0,:1,:2,:3,:4,:5,:6,:7,:8,:9,:10,:11,:12,:13,:14,:15,:16,:17,:18,:19,:20,:21,:22,:23,:24,:25,:26,:27,:28,:29,:30,:31,:32,:33,:34,:35,:36,:37,:38,:39,:40,:41,:42,:43,:44,:45,:46,:47,:48,:49,:50,:51,:52,:53,:54,:55,:56,:57,:58,:59,:60,:61,:62,:63,:64)
当我尝试执行上述 SQL 时,出现以下错误
ORA-01008: not all variables bound
当我尝试使用相同的方法进行如下所示的简单 INSERT 时,效果非常好:
sql = "INSERT INTO PWC_ADMIN.{}({}) VALUES({})" \
.format(self.source_table_name, col_names_as_str, col_list_from_df_as_str)
包括我正在尝试合并的table的DDL供参考:
CREATE TABLE "schema"."table"
( "FILE_ID_2" VARCHAR2(3 CHAR),
"SOURCE_SYSTEM_ID" VARCHAR2(30 CHAR),
"ACCOUNT_NUMBER_PART1" VARCHAR2(7 CHAR),
"ACCOUNT_NUMBER_PART2" VARCHAR2(4 CHAR),
"CONTACT_TYPE" VARCHAR2(4 CHAR),
"CDM_ACTION_CODE" VARCHAR2(3 CHAR),
"ACCOUNT_HOLDER_NAME" VARCHAR2(100 CHAR),
"CREDIT_CARD_TYPE" VARCHAR2(2 CHAR),
"CARD_HOLDER_NAME" VARCHAR2(50),
"CC_TOKEN" VARCHAR2(24 CHAR),
"CREDIT_CARD_MASKED" VARCHAR2(19 CHAR),
"CREDIT_CARD_EXPIRY" VARCHAR2(4 CHAR),
"BP_ROLE" VARCHAR2(6 CHAR),
"BP_ROLE_END_DATE" VARCHAR2(8 CHAR),
"CUST_CREDIT_STATUS" CHAR(1),
"BLOCKED_REASON" VARCHAR2(25 CHAR),
"CREDIT_LIMIT" NUMBER(11,2),
"ANALYST_OR_COLLECTOR_COD" VARCHAR2(4 CHAR),
"CREDIT_REVIEW_DATE" NUMBER(7,0),
"STOP_ORDER_ENTRY" CHAR(1),
"EMAIL_ADDRESS" VARCHAR2(50 CHAR),
"CITY_NAME" VARCHAR2(24 CHAR),
"COUNTRY_CODE" VARCHAR2(4 CHAR),
"FAX_NUMBER" VARCHAR2(15 CHAR),
"PO_BOX" VARCHAR2(25 CHAR),
"CITY_POSTAL_CODE" VARCHAR2(9 CHAR),
"STATE_CODE" VARCHAR2(2 CHAR),
"ADDRESS_LINE_2" VARCHAR2(50 CHAR),
"ADDRESS_LINE_1" VARCHAR2(50 CHAR),
"TELEPHONE_NUMBER" VARCHAR2(15 CHAR),
"LAST_NAME" VARCHAR2(30 CHAR),
"FIRST_NAME" VARCHAR2(20 CHAR),
"CONTACT_PERSON_FUNC" VARCHAR2(2 CHAR),
"NOTES" VARCHAR2(60 CHAR),
"SALUTATION" VARCHAR2(2 CHAR),
"VALID_FROM" VARCHAR2(8 CHAR),
"VALID_TO" VARCHAR2(8 CHAR),
"BUSINESS_PARTNER_REL" VARCHAR2(6 CHAR),
"RECONCILIATION_ACCNT" VARCHAR2(8 CHAR),
"CUST_SERV_CONT_SALUT" CHAR(1),
"STATEMENT_CODE" CHAR(1),
"TERMS_CODE" VARCHAR2(2 CHAR),
"DUNNING_LEVEL" CHAR(1),
"DUNNING_BLOCK" CHAR(1),
"CURRENT_DUNNING_LVL" CHAR(1),
"UC_FLAG" CHAR(1),
"CUSTOMER_CITY" VARCHAR2(24 CHAR),
"CUSTOMER_COUNTRY_COD" VARCHAR2(4 CHAR),
"CUSTOMER_FAX_NUM" VARCHAR2(15 CHAR),
"CUSTOMER_PO_BOX" VARCHAR2(25 CHAR),
"CUSTOMER_ZIP_CODE" VARCHAR2(9 CHAR),
"CUSTOMER_STATE" VARCHAR2(2 CHAR),
"CUSTOMER_ADDR_LINE_2" VARCHAR2(30 CHAR),
"CUSTOMER_ADDR_LINE_1" VARCHAR2(30 CHAR),
"COMPANY_NAME" VARCHAR2(50 CHAR),
"VALIDITY_START_DATE" VARCHAR2(8 CHAR),
"VALIDITY_END_DATE" VARCHAR2(8 CHAR),
"VALIDEND_BP_ROLE_DATE" VARCHAR2(8 CHAR),
"EXTERNAL_ACCT_NUMBER" VARCHAR2(25 CHAR),
"SOURCE_SYSTEM_NAME" VARCHAR2(10 CHAR),
"PROCESS_FLAG" CHAR(1),
"FILE_NM" VARCHAR2(256 CHAR),
"FILE_LOAD_DATE" DATE,
"IND_ORG_FLAG" CHAR(1),
"LEGACY_ID" VARCHAR2(25 CHAR)
);
我已经尝试在 SO 和其他地方寻找原因,并尝试调试我是否遗漏了我在 SQL 中替换的那些列表中的任何内容,我无法成功。有没有人遇到过这类问题?如果有任何帮助,我们将不胜感激。
如果您只绑定一次变量,会更容易和更易读,如下所示:
for i, row in dataset.iterrows():
merge_sql = "MERGE INTO schema.{} dst " \
"USING (SELECT {} DUAL) src " \
"ON ( dst.SOURCE_SYSTEM_ID = src.SOURCE_SYSTEM_ID ) " \
"WHEN MATCHED THEN UPDATE SET {} " \
"WHEN NOT MATCHED THEN INSERT({}) VALUES({})".format(self.source_table_name,
using_stmt_sql_list_as_str,
set_stmt_sql_list_as_str,
col_names_as_str,
col_names_as_str)
oracle_cursor.execute(merge_sql, tuple(row))
其中 using_stmt_sql_list_as_str
是
:0 as FILE_ID_2
:1 as SOURCE_SYSTEM_ID
:2 as ACCOUNT_NUMBER_PART1
:3 as ACCOUNT_NUMBER_PART2
:4 as CONTACT_TYPE
:5 as CDM_ACTION_CODE
:6 as ACCOUNT_HOLDER_NAME
:7 as CREDIT_CARD_TYPE
:8 as CARD_HOLDER_NAME
:9 as CC_TOKEN
:10 as CREDIT_CARD_MASKED
:11 as CREDIT_CARD_EXPIRY
:12 as BP_ROLE
:13 as BP_ROLE_END_DATE
:14 as CUST_CREDIT_STATUS
:15 as BLOCKED_REASON
:16 as CREDIT_LIMIT
:17 as ANALYST_OR_COLLECTOR_COD
:18 as CREDIT_REVIEW_DATE
:19 as STOP_ORDER_ENTRY
:20 as EMAIL_ADDRESS
:21 as CITY_NAME
:22 as COUNTRY_CODE
:23 as FAX_NUMBER
:24 as PO_BOX
:25 as CITY_POSTAL_CODE
:26 as STATE_CODE
:27 as ADDRESS_LINE_2
:28 as ADDRESS_LINE_1
:29 as TELEPHONE_NUMBER
:30 as LAST_NAME
:31 as FIRST_NAME
:32 as CONTACT_PERSON_FUNC
:33 as NOTES
:34 as SALUTATION
:35 as VALID_FROM
:36 as VALID_TO
:37 as BUSINESS_PARTNER_REL
:38 as RECONCILIATION_ACCNT
:39 as CUST_SERV_CONT_SALUT
:40 as STATEMENT_CODE
:41 as TERMS_CODE
:42 as DUNNING_LEVEL
:43 as DUNNING_BLOCK
:44 as CURRENT_DUNNING_LVL
:45 as UC_FLAG
:46 as CUSTOMER_CITY
:47 as CUSTOMER_COUNTRY_COD
:48 as CUSTOMER_FAX_NUM
:49 as CUSTOMER_PO_BOX
:50 as CUSTOMER_ZIP_CODE
:51 as CUSTOMER_STATE
:52 as CUSTOMER_ADDR_LINE_2
:53 as CUSTOMER_ADDR_LINE_1
:54 as COMPANY_NAME
:55 as VALIDITY_START_DATE
:56 as VALIDITY_END_DATE
:57 as VALIDEND_BP_ROLE_DATE
:58 as EXTERNAL_ACCT_NUMBER
:59 as SOURCE_SYSTEM_NAME
:60 as PROCESS_FLAG
:61 as FILE_NM
:62 as FILE_LOAD_DATE
:63 as IND_ORG_FLAG
:64 as LEGACY_ID
和set_stmt_sql_list_as_str
:
dst.FILE_ID_2=src.FILE_ID_2,
dst.ACCOUNT_NUMBER_PART1=src.ACCOUNT_NUMBER_PART1,
dst.ACCOUNT_NUMBER_PART2=src.ACCOUNT_NUMBER_PART2,
dst.CONTACT_TYPE=src.CONTACT_TYPE,
dst.CDM_ACTION_CODE=src.CDM_ACTION_CODE,
dst.ACCOUNT_HOLDER_NAME=src.ACCOUNT_HOLDER_NAME,
dst.CREDIT_CARD_TYPE=src.CREDIT_CARD_TYPE,
dst.CARD_HOLDER_NAME=src.CARD_HOLDER_NAME,
dst.CC_TOKEN=src.CC_TOKEN,
dst.CREDIT_CARD_MASKED=src.CREDIT_CARD_MASKED,
dst.CREDIT_CARD_EXPIRY=src.CREDIT_CARD_EXPIRY,
dst.BP_ROLE=src.BP_ROLE,
dst.BP_ROLE_END_DATE=src.BP_ROLE_END_DATE,
dst.CUST_CREDIT_STATUS=src.CUST_CREDIT_STATUS,
dst.BLOCKED_REASON=src.BLOCKED_REASON,
dst.CREDIT_LIMIT=src.CREDIT_LIMIT,
dst.ANALYST_OR_COLLECTOR_COD=src.ANALYST_OR_COLLECTOR_COD,
dst.CREDIT_REVIEW_DATE=src.CREDIT_REVIEW_DATE,
dst.STOP_ORDER_ENTRY=src.STOP_ORDER_ENTRY,
dst.EMAIL_ADDRESS=src.EMAIL_ADDRESS,
dst.CITY_NAME=src.CITY_NAME,
dst.COUNTRY_CODE=src.COUNTRY_CODE,
dst.FAX_NUMBER=src.FAX_NUMBER,
dst.PO_BOX=src.PO_BOX,
dst.CITY_POSTAL_CODE=src.CITY_POSTAL_CODE,
dst.STATE_CODE=src.STATE_CODE,
dst.ADDRESS_LINE_2=src.ADDRESS_LINE_2,
dst.ADDRESS_LINE_1=src.ADDRESS_LINE_1,
dst.TELEPHONE_NUMBER=src.TELEPHONE_NUMBER,
dst.LAST_NAME=src.LAST_NAME,
dst.FIRST_NAME=src.FIRST_NAME,
dst.CONTACT_PERSON_FUNC=src.CONTACT_PERSON_FUNC,
dst.NOTES=src.NOTES,
dst.SALUTATION=src.SALUTATION,
dst.VALID_FROM=src.VALID_FROM,
dst.VALID_TO=src.VALID_TO,
dst.BUSINESS_PARTNER_REL=src.BUSINESS_PARTNER_REL,
dst.RECONCILIATION_ACCNT=src.RECONCILIATION_ACCNT,
dst.CUST_SERV_CONT_SALUT=src.CUST_SERV_CONT_SALUT,
dst.STATEMENT_CODE=src.STATEMENT_CODE,
dst.TERMS_CODE=src.TERMS_CODE,
dst.DUNNING_LEVEL=src.DUNNING_LEVEL,
dst.DUNNING_BLOCK=src.DUNNING_BLOCK,
dst.CURRENT_DUNNING_LVL=src.CURRENT_DUNNING_LVL,
dst.UC_FLAG=src.UC_FLAG,
dst.CUSTOMER_CITY=src.CUSTOMER_CITY,
dst.CUSTOMER_COUNTRY_COD=src.CUSTOMER_COUNTRY_COD,
dst.CUSTOMER_FAX_NUM=src.CUSTOMER_FAX_NUM,
dst.CUSTOMER_PO_BOX=src.CUSTOMER_PO_BOX,
dst.CUSTOMER_ZIP_CODE=src.CUSTOMER_ZIP_CODE,
dst.CUSTOMER_STATE=src.CUSTOMER_STATE,
dst.CUSTOMER_ADDR_LINE_2=src.CUSTOMER_ADDR_LINE_2,
dst.CUSTOMER_ADDR_LINE_1=src.CUSTOMER_ADDR_LINE_1,
dst.COMPANY_NAME=src.COMPANY_NAME,
dst.VALIDITY_START_DATE=src.VALIDITY_START_DATE,
dst.VALIDITY_END_DATE=src.VALIDITY_END_DATE,
dst.VALIDEND_BP_ROLE_DATE=src.VALIDEND_BP_ROLE_DATE,
dst.EXTERNAL_ACCT_NUMBER=src.EXTERNAL_ACCT_NUMBER,
dst.SOURCE_SYSTEM_NAME=src.SOURCE_SYSTEM_NAME,
dst.PROCESS_FLAG=src.PROCESS_FLAG,
dst.FILE_NM=src.FILE_NM,
dst.FILE_LOAD_DATE=src.FILE_LOAD_DATE,
dst.IND_ORG_FLAG=src.IND_ORG_FLAG,
dst.LEGACY_ID=src.LEGACY_ID
即,您需要跳过 dst.SOURCE_SYSTEM_ID=src.SOURCE_SYSTEM_ID,
,因为您无法更改用于 ON(...)
匹配条件的列。
因此您的最终合并语句如下所示:
MERGE INTO schema.table dst
USING ( select
:0 as FILE_ID_2,
:1 as SOURCE_SYSTEM_ID,
:2 as ACCOUNT_NUMBER_PART1,
:3 as ACCOUNT_NUMBER_PART2,
:4 as CONTACT_TYPE,
...
from DUAL) src
ON ( dst.SOURCE_SYSTEM_ID = src.SOURCE_SYSTEM_ID )
WHEN MATCHED THEN UPDATE SET
dst.FILE_ID_2=src.FILE_ID_2,
dst.ACCOUNT_NUMBER_PART1=src.ACCOUNT_NUMBER_PART1,
dst.ACCOUNT_NUMBER_PART2=src.ACCOUNT_NUMBER_PART2,
...
WHEN NOT MATCHED THEN INSERT(FILE_ID_2,SOURCE_SYSTEM_ID,ACCOUNT_NUMBER_PART1,ACCOUNT_NUMBER_PART2,CONTACT_TYPE,CDM_ACTION_CODE,ACCOUNT_HOLDER_NAME,CREDIT_CARD_TYPE,CARD_HOLDER_NAME,CC_TOKEN,CREDIT_CARD_MASKED,CREDIT_CARD_EXPIRY,BP_ROLE,BP_ROLE_END_DATE,CUST_CREDIT_STATUS,BLOCKED_REASON,CREDIT_LIMIT,ANALYST_OR_COLLECTOR_COD,CREDIT_REVIEW_DATE,STOP_ORDER_ENTRY,EMAIL_ADDRESS,CITY_NAME,COUNTRY_CODE,FAX_NUMBER,PO_BOX,CITY_POSTAL_CODE,STATE_CODE,ADDRESS_LINE_2,ADDRESS_LINE_1,TELEPHONE_NUMBER,LAST_NAME,FIRST_NAME,CONTACT_PERSON_FUNC,NOTES,SALUTATION,VALID_FROM,VALID_TO,BUSINESS_PARTNER_REL,RECONCILIATION_ACCNT,CUST_SERV_CONT_SALUT,STATEMENT_CODE,TERMS_CODE,DUNNING_LEVEL,DUNNING_BLOCK,CURRENT_DUNNING_LVL,UC_FLAG,CUSTOMER_CITY,CUSTOMER_COUNTRY_COD,CUSTOMER_FAX_NUM,CUSTOMER_PO_BOX,CUSTOMER_ZIP_CODE,CUSTOMER_STATE,CUSTOMER_ADDR_LINE_2,CUSTOMER_ADDR_LINE_1,COMPANY_NAME,VALIDITY_START_DATE,VALIDITY_END_DATE,VALIDEND_BP_ROLE_DATE,EXTERNAL_ACCT_NUMBER,SOURCE_SYSTEM_NAME,PROCESS_FLAG,FILE_NM,FILE_LOAD_DATE,IND_ORG_FLAG,LEGACY_ID)
VALUES(FILE_ID_2,SOURCE_SYSTEM_ID,ACCOUNT_NUMBER_PART1,ACCOUNT_NUMBER_PART2,CONTACT_TYPE,CDM_ACTION_CODE,ACCOUNT_HOLDER_NAME,CREDIT_CARD_TYPE,CARD_HOLDER_NAME,CC_TOKEN,CREDIT_CARD_MASKED,CREDIT_CARD_EXPIRY,BP_ROLE,BP_ROLE_END_DATE,CUST_CREDIT_STATUS,BLOCKED_REASON,CREDIT_LIMIT,ANALYST_OR_COLLECTOR_COD,CREDIT_REVIEW_DATE,STOP_ORDER_ENTRY,EMAIL_ADDRESS,CITY_NAME,COUNTRY_CODE,FAX_NUMBER,PO_BOX,CITY_POSTAL_CODE,STATE_CODE,ADDRESS_LINE_2,ADDRESS_LINE_1,TELEPHONE_NUMBER,LAST_NAME,FIRST_NAME,CONTACT_PERSON_FUNC,NOTES,SALUTATION,VALID_FROM,VALID_TO,BUSINESS_PARTNER_REL,RECONCILIATION_ACCNT,CUST_SERV_CONT_SALUT,STATEMENT_CODE,TERMS_CODE,DUNNING_LEVEL,DUNNING_BLOCK,CURRENT_DUNNING_LVL,UC_FLAG,CUSTOMER_CITY,CUSTOMER_COUNTRY_COD,CUSTOMER_FAX_NUM,CUSTOMER_PO_BOX,CUSTOMER_ZIP_CODE,CUSTOMER_STATE,CUSTOMER_ADDR_LINE_2,CUSTOMER_ADDR_LINE_1,COMPANY_NAME,VALIDITY_START_DATE,VALIDITY_END_DATE,VALIDEND_BP_ROLE_DATE,EXTERNAL_ACCT_NUMBER,SOURCE_SYSTEM_NAME,PROCESS_FLAG,FILE_NM,FILE_LOAD_DATE,IND_ORG_FLAG,LEGACY_ID)