You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Airflow中OracleStoredProcedureOperator传DATE类型运行时参数问题

问题背景

在Apache Airflow中开发需接收运行时参数batch_dt的任务时,使用OracleStoredProcedureOperator调用Oracle存储过程,存储过程所有入参均为数据库DATE类型,定义如下:

procedure use_dates (
    i_date  in date,
    i_date2 in date,
    i_date3 in date
  );

要求传参方案不依赖数据库当前NLS设置,现有尝试均执行失败:

  • 直接传入Airflow宏{{ dag_run.conf['batch_dt'] }}或{{ macros.datetime.strptime(dag_run.conf['batch_dt'], '%Y-%m-%d') }}时,宏始终返回字符串类型,触发报错ORA-01861: literal does not match format string
  • 传入拼接的to_date('{{ dag_run.conf['batch_dt'] }}', 'DD-MM-YYYY')字符串时,触发报错ORA-01858: a non-numeric character was found where a numeric was expected
  • 直接在任务参数中配置date.today()可正常执行,但属于代码固定值,无法满足运行时动态传参需求

原有问题代码如下:

res_task = OracleStoredProcedureOperator(
    task_id = 'mytask',
    procedure = 'use_dates',
    parameters = 
        {"i_date": date.today(), # 可执行但不是动态运行时值
        "i_date2": "to_date('{{ dag_run.conf['batch_dt'] }}', 'DD-MM-YYYY')", 
        # 传入值为字符串"to_date('13-06-2022', 'DD-MM-YYYY')",触发ORA-01858错误
        "i_date3": "{{ macros.datetime.strptime(dag_run.conf['batch_dt'], '%Y-%m-%d' ) }}"
        # 传入值为字符串'2022-06-13 00:00:00',触发ORA-01861错误
        }
    )

已知Airflow宏默认返回字符串类型,需要该场景下的可行实现方案。

失败原因说明
  1. 直接传宏渲染的字符串报错:数据库端将字符串转为DATE类型时会读取当前NLS_DATE_FORMAT配置,格式不匹配就会抛出ORA-01861,不符合不依赖NLS设置的要求
  2. 传拼接的to_date()字符串报错:OracleStoredProcedureOperator采用绑定变量模式传参,参数值会被作为纯值传入,不会被当做SQL片段解析执行,因此to_date()函数不会被数据库运行,字符串直接传给DATE类型入参自然触发类型转换错误
  3. date.today()可正常执行的原因:Python原生date/datetime对象传入后,底层Oracle驱动(cx_Oracle/python-oracledb)会自动完成类型映射,不需要依赖数据库NLS设置做字符串转日期的操作。
可行解决方案

Airflow 2.1及以上版本支持DAG级别的原生对象渲染配置,开启后Jinja模板的渲染结果不会被强制转为字符串,会保留原生Python类型,刚好适配这个场景。

实现步骤

  1. 在DAG初始化时添加参数*render_template_as_native_obj=True*,开启原生对象渲染
  2. 存储过程的日期参数直接用macros.datetime.strptime解析运行时batch_dt,渲染后会直接得到Python datetime对象,驱动会自动映射为Oracle DATE类型,全程无NLS依赖。

正确代码示例

from datetime import datetime, date
from airflow import DAG
from airflow.providers.oracle.operators.stored_procedure import OracleStoredProcedureOperator

with DAG(
    dag_id="call_oracle_sp_with_runtime_dt",
    start_date=datetime(2024, 1, 1),
    schedule=None,
    # 核心配置:开启原生对象渲染,Jinja输出保留原Python类型
    render_template_as_native_obj=True,
    catchup=False
) as dag:
    res_task = OracleStoredProcedureOperator(
        task_id="mytask",
        procedure="use_dates",
        parameters={
            "i_date": date.today(),
            # 渲染后得到Python datetime对象,驱动自动适配Oracle DATE类型
            "i_date2": "{{ macros.datetime.strptime(dag_run.conf['batch_dt'], '%Y-%m-%d') }}",
            "i_date3": "{{ macros.datetime.strptime(dag_run.conf['batch_dt'], '%Y-%m-%d') }}"
        }
    )

替代方案(不开启全局原生渲染)

如果不想在整个DAG层面开启原生对象渲染,可以新增前置Python任务,将运行时batch_dt解析为datetime对象后通过XCom传递给存储过程任务,核心逻辑一致:只要传入parameters的是Python原生date/datetime对象,就可以被驱动正确识别,不会触发NLS相关报错。

注意:永远不要在OracleStoredProcedureOperator的参数值中拼接SQL函数(如to_date、sysdate等),绑定变量传参模式下这类内容不会被当做SQL执行,只会被当做普通字符串值传入。


内容的提问来源于stack exchange,提问作者Ivan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 16:48:29