【问题标题】:Oracle passing a variable to a functionOracle 将变量传递给函数
【发布时间】:2021-07-25 07:27:58
【问题描述】:

我有一些使用硬编码日期的 SQL 代码。我的目标是删除硬编码的日期并用变量替换它们以使代码通用。

我的测试用例如下;

    CREATE OR REPLACE FUNCTION IsDate( p_str IN VARCHAR2, p_format IN VARCHAR2 ) RETURN NUMBER AS
   V_date DATE;
   BEGIN
      V_Date := TO_DATE( p_str, p_format );
       RETURN 1;
    EXCEPTION
      WHEN OTHERS THEN
         RETURN 0;
    END;

这很好用

   select IsDate(DATE '2021-07-31','YYYY-MM-DD') from dual;

这会导致错误(见下文)。有人可以解释这个问题以及如何解决它。 我正在测试实时 SQL。提前感谢所有回答的人。

   exec :my_date :=  DATE '2021-07-31';
   select IsDate( DATE my_date,'YYYY-MM-DD') from dual;

我遇到了错误

ORA-01008:并非所有变量都绑定 ORA-06512:在“SYS.DBMS_SQL”,第 1721 行
ORA-00936: 缺少表达式

【问题讨论】:

  • 您的过程采用两个varchar2 输入参数,但您将date 作为第一个参数传递。为什么? date .... 还假定它后面有一个文本常量文字,因为它构成了一个日期文字
  • 你的 oracle 版本是什么?
  • 我的目标是摆脱调用函数中的硬编码日期,并在调用函数中使用变量。您能否提供有关如何实现此目的的详细回复?我正在使用实时 sql 进行测试
  • “我的目标是摆脱硬编码的日期” - 所以你需要一些类似日期的字符串的来源。它是什么?你的“约会”从何而来?
  • 我希望用户像在我的 exec 示例中一样传递日期。也许我需要一个 PLSQL 包装器来调用我的 sql 代码?我希望我的 sql 代码是变量,而不是硬编码的日期。底线是我不希望用户修改任何代码。我希望我能充分解释我的问题。感谢您的耐心和专业知识

标签: sql oracle function data-binding


【解决方案1】:

自 12.2 以来有一个特殊功能 VALIDATE_CONVERSION 可以完全满足您的要求: VALIDATE_CONVERSION

例子:

SQL> select VALIDATE_CONVERSION('01-01-2000' as date,'dd-mm-yyyy') chk1 from dual;

      CHK1
----------
         1

SQL> select VALIDATE_CONVERSION('01-01-2000' as date,'yyyy-mm-dd') chk2 from dual;

      CHK2
----------
         0

livesql.oracle.com 也不支持exec 命令,这是一个 SQL*Plus 命令。所以如果你想用绑定变量测试你的函数,你可以使用简单的 PL/SQL 变量:

declare
    string_date varchar2(100);
    
    FUNCTION IsDate( p_str IN VARCHAR2, p_format IN VARCHAR2 ) RETURN NUMBER AS
        V_date DATE;
    BEGIN
        V_Date := TO_DATE( p_str, p_format );
        RETURN 1;
    EXCEPTION
        WHEN OTHERS THEN
            RETURN 0;
    END;
begin
    string_date:='31-12-2000';
    dbms_output.put_line(IsDate(string_date,'dd-mm-yyyy'));
end;
/

【讨论】:

  • 如何将 2 个日期传递给 sql 代码?在我的 sql 代码中,将日期作为变量引用,即 start_date、end_date。我正在尝试创建通用代码。我不希望用户每次需要新的 start_date 和 end_date 时都修改代码。我希望他们以某种方式传递日期。这就是我用 exec 命令尝试的。感谢您的帮助和专业知识
  • @Beefstu 通行证日期从什么开始? Java、Python、SQL*Plus 脚本、另一个 PL/SQL 过程?
  • 一个 PLSQL 过程.. 我设想使用它作为我的 SQL 代码的包装器。然后在我的 SQL 代码中,我不需要硬编码的日期。这样,如果他们想要不同的 start_date 和 end_date,就没有人需要编辑代码了。这样行吗?
  • @Beefstu 该过程可以返回一个引用光标。会这样吗?
  • @William 我正在使用管道 proc 来生成日期范围,该范围效果很好并且不想更改。由于这里的 cmets 有限,也许我应该开始一个新线程
【解决方案2】:

DATE 关键字需要文字,您不能使用字符串变量。

关于你的功能:

FUNCTION IsDate( p_str IN VARCHAR2, p_format IN VARCHAR2 ) RETURN NUMBER

它需要两个VARCHAR2,即字符串值。但是,当您运行 IsDate(DATE '2021-07-31','YYYY-MM-DD') 时,您会将 DATE 值传递给函数,而不是字符串。

检查DATE 值的格式是没有意义的,因为DATE 值本身没有格式,它被存储为内部二进制值。永远不要对已经是 DATE 的值使用 TO_DATE。函数TO_DATE 需要一个字符串,该字符串应转换为DATE

当您选择DATE显示的内容由您当前的用户会话NLS_DATE_FORMAT 设置定义(默认情况下)。您可以更改默认输出格式,例如使用 ALTER SESSION SET NLS_DATE_FORMAT = 'DD.MM.YYYY'; 或使用 TO_CHAR() 函数显式设置。

当您调用函数IsDate(DATE '2021-07-31','YYYY-MM-DD') 时,Oracle 会隐式转换为字符串。即它运行

V_Date := TO_DATE( TO_CHAR(p_str, SYS_CONTEXT('USERENV', 'NLS_DATE_FORMAT')), p_format );

当你传递一个DATE 值时,你的函数实际上是这样的:

CREATE OR REPLACE FUNCTION IsDate( p_str IN VARCHAR2, p_format IN VARCHAR2 ) RETURN NUMBER AS
   ret NUMBER;
BEGIN
   SELECT COUNT(*)
   INTO ret
   FROM NLS_SESSION_PARAMETERS
   WHERE PARAMETER = 'NLS_DATE_FORMAT'
     AND VALUE = p_format;
   RETURN ret; 
   -- p_str is ignored completely
END;

注意,在 Oracle 18 中,TO_DATE 函数提供了 DEFAULT ... ON CONVERSION ERROR 子句,因此编写额外的函数可能有点过头了。

【讨论】:

  • 感谢您的详细回复。我的目标是尝试摆脱调用代码中的硬编码日期参数,并将其作为调用代码中的变量而不是文字进行引用。这可以做到吗?如果是这样,您能否提供端到端的示例。我在示例中尝试了您的功能,但它在实时 sql 中不起作用
  • 不清楚您所说的“摆脱调用代码中的硬编码日期参数”是什么意思。你有例子吗?
  • 我的原始帖子显示了导致错误的第二种情况的示例。 livesql.oracle.com 也不支持 exec 命令,它是一个 SQL*Plus 命令。我希望将变量传递给 SQL 代码或创建 PLSQL 设置日期并调用我的 SQL 代码。我不想在我的 sql 代码中输入一个硬编码的日期,我想传入一个。希望这能增加我的请求的清晰度。感谢您的回答
  • 第二种情况IsDate( DATE my_date,'YYYY-MM-DD')是SQL语法错误。修复代码,任何功能都无法阻止。如果您喜欢使用变量,请使用IsDate( my_date,'YYYY-MM-DD') - 变量是my_date。但如前所述,这是完全没有意义的,DATE 值没有您可以验证的格式。
  • 这就是我想要做的。 stackoverflow.com/questions/68519898/…
猜你喜欢
  • 2020-07-28
  • 1970-01-01
  • 1970-01-01
  • 2012-03-02
  • 2011-01-18
  • 2015-05-02
  • 2015-12-17
  • 2013-04-20
相关资源
最近更新 更多