如何使用Airflow OracleOperator的多个语句执行sql脚本

时间:2019-06-18 18:40:50

标签: python-3.x airflow

我正在尝试使用多个语句(由;分隔)调用一个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模板不适用于多条语句。任何帮助将不胜感激 。谢谢!!

2 个答案:

答案 0 :(得分:0)

您可以分配字符串格式sql语句,而不是sql文件” 以下是气流中Oracle操作的原始API文档。 sql可以是str或str列表。如果您更喜欢使用文件模板,则需要使用参数呈现文件模板。 注意:气流使用jinjia2作为模板租用。

oracle_operator API

  

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(无,...)处理最后一个分号,否则操作员会将空命令提交给数据库,然后出错。