我正在尝试使用多个语句(由;分隔)调用一个sql文件。通过气流中的OracleOperator进行操作,但使用多个语句给出以下错误
例如包含文件
CALL DROP_OBJECTS('TABLE_XYZ');
从DUAL中创建TABLE TABLE_XYZ AS SELECT 1 Dummy;
[2019-06-18 18:19:12,582] { init .py:1580}错误-ORA-00933:SQL命令未正确结束 追溯(最近一次通话): _run_raw_task中的文件“ /usr/local/lib/python3.6/site-packages/airflow/models/init.py”,第1441行 结果= task_copy.execute(context = context) 执行中的文件“ /usr/local/lib/python3.6/site-packages/airflow/operators/oracle_operator.py”,第63行 参数= self.parameters) 运行中的文件“ /usr/local/lib/python3.6/site-packages/airflow/hooks/dbapi_hook.py”,第172行 cur.execute(s) cx_Oracle.DatabaseError:ORA-00933:SQL命令未正确结束
即使单个语句以;结尾给出以下错误:
例如文件
从DUAL中创建TABLE TABLE_XYZ AS SELECT 1 Dummy;
[2019-06-18 17:47:53,137] { init .py:1580}错误-ORA-00922:缺少或无效的选项 追溯(最近一次通话): _run_raw_task中的文件“ /usr/local/lib/python3.6/site-packages/airflow/models/init.py”,第1441行 结果= task_copy.execute(context = context) 执行中的文件“ /usr/local/lib/python3.6/site-packages/airflow/operators/oracle_operator.py”,第63行 参数= self.parameters) 运行中的文件“ /usr/local/lib/python3.6/site-packages/airflow/hooks/dbapi_hook.py”,第172行 cur.execute(s)
with DAG('my_simple_dag',
default_args=default_args,
template_searchpath=['/root/rahul/'],
schedule_interval='*/10 * * * *',
) as dag:
opr_oracle = OracleOperator(task_id='oracleTest',oracle_conn_id='STG',
sql='test.sql')
我是否需要传递任何其他参数以使dbhook理解该文件需要在单独的语句中拆分?
根据其预期的文档 param sql:要执行的sql代码。可以接收代表sql语句的str, str(SQL语句)列表或对模板文件的引用。 模板引用由以'.sql'结尾的str识别 (已模板化)
,但是.sql模板不适用于多条语句。任何帮助将不胜感激 。谢谢!!
答案 0 :(得分:0)
您可以分配字符串格式sql语句,而不是sql文件” 以下是气流中Oracle操作的原始API文档。 sql可以是str或str列表。如果您更喜欢使用文件模板,则需要使用参数呈现文件模板。 注意:气流使用jinjia2作为模板租用。
sql(str或list [str])–要执行的sql代码。可以接收表示sql语句的str,str列表(sql语句)或 引用模板文件。模板引用由str识别 以“ .sql”(已模板化)结尾的
oracle_conn_id(str)–引用特定的Oracle数据库
参数(映射或可迭代)–(可选)要呈现的参数 SQL查询。
autocommit(布尔)–如果为True,则自动提交每个命令。 (默认值:False)
答案 1 :(得分:0)
Oracle Operator将获取已模板化的SQL字符串的列表。
我所做的是将SQL文件读取为文本文件,然后将其分割为';'创建一个字符串列表。
with open('/home/airflow/airflow/dags/sql/test_multi.sql') as sql_file:
sql_list = list(filter(None, sql_file.read().split(';')))
t_run_sql = OracleOperator(task_id='run_sql',
sql=sql_list,
oracle_conn_id='user_id',
autocommit=True,
depends_on_past=True,
dag=dag)
我使用模板进行了测试(是的,如果没有先创建表,这将在Oracle中失败):
drop table test_multi;
create table test_multi as
select
{{ macros.datetime.strftime(execution_date.in_tz('Australia/Sydney') + macros.timedelta(days=1),'%Y%m%d') }} as day1,
{{ macros.datetime.strftime(execution_date.in_tz('Australia/Sydney') + macros.timedelta(days=2),'%Y%m%d') }} as day2,
{{ macros.datetime.strftime(execution_date.in_tz('Australia/Sydney') + macros.timedelta(days=3),'%Y%m%d') }} as day3
from dual;
insert into test_multi
select
{{ macros.datetime.strftime(execution_date.in_tz('Australia/Sydney') + macros.timedelta(days=4),'%Y%m%d') }} as day1,
{{ macros.datetime.strftime(execution_date.in_tz('Australia/Sydney') + macros.timedelta(days=5),'%Y%m%d') }} as day2,
{{ macros.datetime.strftime(execution_date.in_tz('Australia/Sydney') + macros.timedelta(days=6),'%Y%m%d') }} as day3
from dual;
此解决方案存在一个问题,即需要确保您的SQL在其他任何地方都不包含分号。我还认为分割'; / n'可能会更好,但它要求用户始终在';'之后开始换行,因此仍然不理想。
我还发现我需要使用filter(无,...)处理最后一个分号,否则操作员会将空命令提交给数据库,然后出错。