如何使用 cx_oracle 执行 SQL 脚本
How to execute a SQL script with cx_oracle
我正在尝试在 Oracle 数据库上执行 SQL 脚本(从文件中读取)。我尝试了很多方法,但 none 有效。
我有以下方法:
def connect_cx_oracle():
dns_tns = cx_Oracle.makedsn(config.DB_HOST, config.DB_PORT, service_name=config.DB_DBASE)
con = cx_Oracle.connect(user=config.DB_USERNAME, password=config.DB_PASSWORD, dsn=dns_tns)
cur = con.cursor()
fd = open('PurgeProcess_2.sql')
full_sql = fd.read()
cur.prepare(full_sql)
cur.executemany(None, full_sql)
con.commit()
对文件使用 cur.execute 会导致错误。我不能用分号分割文件,因为它是一个脚本。
sql 文件的代码是这样的(不发布整个文件)
SET SERVEROUTPUT ON SIZE UNLIMITED;
DECLARE
CURSOR c_task IS SELECT job_id, task_info_id FROM task WHERE job_id <= myjob_id;
BEGIN
dbms_output.ENABLE(NULL);
dbms_output.put_line('*******************************');
dbms_output.put_line('* Purge job started....... ');
dbms_output.put_line('*******************************');
IF (FROM_date < 30) THEN
dbms_output.put_line(' ');
end IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line(' ');
dbms_output.put_line('*******************************');
dbms_output.put_line('* Purge job completed....... ');
dbms_output.put_line('*******************************');
RAISE NO_ITEMS_TO_PROCESS;
END;
FOR i IN 1..myjobIDnumber.COUNT
LOOP
BEGIN
DELETE FROM job WHERE id = myjobIDnumber(i);
IF SQL%ROWCOUNT > 0 THEN
deletecount4 := deletecount4 + SQL%ROWCOUNT;
END IF;
END;
END LOOP;
dbms_output.put_line('Job table records deleted. Number of records deleted is ' || deletecount4);
dbms_output.put_line(' ');
ROLLBACK;
--COMMIT;
dbms_output.put_line('*******************************');
dbms_output.put_line('* Purge job completed....... *');
dbms_output.put_line('*******************************');
EXCEPTION
WHEN NO_ITEMS_TO_PROCESS THEN
NULL;
WHEN DATE_LIMIT_APPROACHED THEN
NULL;
END;
如果我使用 cur.execute(fileName) 我得到
cx_Oracle.DatabaseError: ORA-00922: missing or invalid option
有了 executemany,我得到了
TypeError: parameters should be a list of sequences/dictionaries or an integer specifying the number of times to execute the statement
我不是一个真正的 sql 人,任何帮助将不胜感激。问候
cx_Oracle和其他类似的驱动程序只能execute one statement at a time. Even executemany()
执行一条语句(但有很多数据值)。
做你想做的最简单的方法是:
从您的 SQL 文件中删除所有 SQL*Plus 特定命令,例如 SET
,因为如果 [=35=,数据库将无法理解它们] 试图处决他们。它们对 cx_Oracle.
毫无意义
始终使用斜线(而不是分号)来终止 SQL 命令(以及 PL/SQL,当然斜线始终是必需的)
写一个类似 RunSqlScript 的方法,从 SQL 文件中读取每个语句并执行它。
一个更明智的解决方案是远离 SQL 文件并将所有语句编码在 cx_Oracle.
中
在尝试了很多库之后,我最终使用 Python 的子流程来解决这个问题。发布代码,因为它可能会在将来帮助某人。
def connect_to_db_and_execute(timeout):
proc = subprocess.Popen(f'sqlplus {config.DB_USERNAME}/{config.DB_PASSWORD}@{config.DB_HOST}:{config.DB_PORT}/'
f'{config.DB_DBASE} @C:/pathtoSql/PurgeProcess_2.sql', stdout=PIPE, stderr=PIPE, universal_newlines=True)
timer = Timer(timeout, proc.kill)
try:
timer.start()
stdout,stderr = proc.communicate()
finally:
timer.cancel()
(output, err) = proc.communicate()
print('output is ', output)
if err:
# iF there is an error, print and sent it via email
print(err)
send_email(email, pword, to_recipients, subject, err)```
我正在尝试在 Oracle 数据库上执行 SQL 脚本(从文件中读取)。我尝试了很多方法,但 none 有效。
我有以下方法:
def connect_cx_oracle():
dns_tns = cx_Oracle.makedsn(config.DB_HOST, config.DB_PORT, service_name=config.DB_DBASE)
con = cx_Oracle.connect(user=config.DB_USERNAME, password=config.DB_PASSWORD, dsn=dns_tns)
cur = con.cursor()
fd = open('PurgeProcess_2.sql')
full_sql = fd.read()
cur.prepare(full_sql)
cur.executemany(None, full_sql)
con.commit()
对文件使用 cur.execute 会导致错误。我不能用分号分割文件,因为它是一个脚本。
sql 文件的代码是这样的(不发布整个文件)
SET SERVEROUTPUT ON SIZE UNLIMITED;
DECLARE
CURSOR c_task IS SELECT job_id, task_info_id FROM task WHERE job_id <= myjob_id;
BEGIN
dbms_output.ENABLE(NULL);
dbms_output.put_line('*******************************');
dbms_output.put_line('* Purge job started....... ');
dbms_output.put_line('*******************************');
IF (FROM_date < 30) THEN
dbms_output.put_line(' ');
end IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line(' ');
dbms_output.put_line('*******************************');
dbms_output.put_line('* Purge job completed....... ');
dbms_output.put_line('*******************************');
RAISE NO_ITEMS_TO_PROCESS;
END;
FOR i IN 1..myjobIDnumber.COUNT
LOOP
BEGIN
DELETE FROM job WHERE id = myjobIDnumber(i);
IF SQL%ROWCOUNT > 0 THEN
deletecount4 := deletecount4 + SQL%ROWCOUNT;
END IF;
END;
END LOOP;
dbms_output.put_line('Job table records deleted. Number of records deleted is ' || deletecount4);
dbms_output.put_line(' ');
ROLLBACK;
--COMMIT;
dbms_output.put_line('*******************************');
dbms_output.put_line('* Purge job completed....... *');
dbms_output.put_line('*******************************');
EXCEPTION
WHEN NO_ITEMS_TO_PROCESS THEN
NULL;
WHEN DATE_LIMIT_APPROACHED THEN
NULL;
END;
如果我使用 cur.execute(fileName) 我得到
cx_Oracle.DatabaseError: ORA-00922: missing or invalid option
有了 executemany,我得到了
TypeError: parameters should be a list of sequences/dictionaries or an integer specifying the number of times to execute the statement
我不是一个真正的 sql 人,任何帮助将不胜感激。问候
cx_Oracle和其他类似的驱动程序只能execute one statement at a time. Even executemany()
执行一条语句(但有很多数据值)。
做你想做的最简单的方法是:
从您的 SQL 文件中删除所有 SQL*Plus 特定命令,例如
SET
,因为如果 [=35=,数据库将无法理解它们] 试图处决他们。它们对 cx_Oracle. 毫无意义
始终使用斜线(而不是分号)来终止 SQL 命令(以及 PL/SQL,当然斜线始终是必需的)
写一个类似 RunSqlScript 的方法,从 SQL 文件中读取每个语句并执行它。
一个更明智的解决方案是远离 SQL 文件并将所有语句编码在 cx_Oracle.
中在尝试了很多库之后,我最终使用 Python 的子流程来解决这个问题。发布代码,因为它可能会在将来帮助某人。
def connect_to_db_and_execute(timeout):
proc = subprocess.Popen(f'sqlplus {config.DB_USERNAME}/{config.DB_PASSWORD}@{config.DB_HOST}:{config.DB_PORT}/'
f'{config.DB_DBASE} @C:/pathtoSql/PurgeProcess_2.sql', stdout=PIPE, stderr=PIPE, universal_newlines=True)
timer = Timer(timeout, proc.kill)
try:
timer.start()
stdout,stderr = proc.communicate()
finally:
timer.cancel()
(output, err) = proc.communicate()
print('output is ', output)
if err:
# iF there is an error, print and sent it via email
print(err)
send_email(email, pword, to_recipients, subject, err)```