【问题标题】:ORA-01861 literal does not match format string error in stored procedureORA-01861 文字与存储过程中的格式字符串不匹配错误
【发布时间】:2017-10-10 17:24:06
【问题描述】:

各位专家,

我们需要根据emp_id查找到期日,

    create table emp_test (emp_id number, customer_due_date date)
    /
    create table dept_test (due_days number)
    /
    insert into emp_test values (1,sysdate)
    /
    insert into emp_test values (2,sysdate-1)
    /
    insert into emp_test values (3,sysdate-2)
    /
    insert into emp_test values (4,sysdate+1)
    /
    insert into emp_test values (5,sysdate+2)
    /
    insert into dept_test values(2)
    /
    commit
    /

我的存储过程:

    create or replace procedure test_proc(p_emp_id in emp_test.emp_id%type,p_due_date out date)
    as
    begin
    select
    (case
    when trim(to_char(trunc(o.customer_due_date) - r,due_days, 'Day')) = 'Sunday' then trunc(o.customer_due_date)-r.due_days-2
    when trim(to_char(trunc(o.customer_due_date) - r.due_days,
    'Day')) = 'Saturday' then trunc(o.customer_due_date)-r.due_days-1
    when trunc(o.customer_due_date) is null then trunc(sysdate) + 60
    else trunc(o.customer_due_date) - r.due_days
    end
    ) Due_date
    into p_due_date
    from
    dept_test r,
    emp_test o
    where o.emp_id = p_emp_id;

    p_due_date := to_char(p_due_date,'yyyy-mm-dd');

    end;

我收到错误,因为“ORA-01861 文字与格式字符串不匹配”。

请建议,我们该如何解决这个错误?

谢谢。

【问题讨论】:

  • p_due_date := to_char(..) 毫无意义。

标签: sql oracle plsql


【解决方案1】:

您在数据类型上玩得又快又松。也许您的编程经验是使用一种(或多种语言)执行/不执行数据类型的语言。

在函数声明中,您说p_due_date 将是DATE 数据类型。但是当你第一次分配它时(通过SELECT ... INTO)你分配一个字符串给它。由于您没有将其包装在适当的 TO_DATE 函数中,Oracle(它有时但并非总是强制执行数据类型,并且它的许多猜测完全错误)试图在分配给p_due_date 之前,使用会话的NLS_DATE_FORMAT 参数将字符串转换为日期。如果这不是(出于某种意外)完全是 'yyyy-mm-dd',您将收到此错误。

执行此操作的正确方法是将CASE 表达式包装在SELECT ... INTO 语句中的TO_DATE() 内。

顺便说一句,稍后在代码中你有TO_CHAR(.....) - 为什么你有这个,完全不清楚。 TO_CHAR 返回一个字符串,但您分配回p_due_date,它必须是DATE,因此您有更多的隐式转换(使用错误的格式模型)。当然,如果你按照我的建议修复了SELECT ... INTO 语句,那么p_due_date 被选中后就不需要做任何事情了;您可以按原样退回。

【讨论】:

  • 能否请您建议我在 select ..into .. 语句中需要更改的内容
  • 我已经做到了。将 case 表达式放在 to_date(...) 内的该选择中,就像您尝试在选择之外执行的操作一样。如果您要求我逐字逐句地为您编写代码,对不起,但我不做那种工作。
  • 我已按照您的建议修改了选择,但较早的日期为 '11-oct-17' 现在它已更改为 '17-oct-11',我需要在 '2017-10- 11' 格式。
  • 选择 to_date( (trim(to_char(trunc(o.customer_due_date) - r,due_days, 'Day')) = 'Sunday' then trunc(o.customer_due_date)-r.due_days- 2 当 trim(to_char(trunc(o.customer_due_date) - r.due_days, 'Day')) = 'Saturday' 然后 trunc(o.customer_due_date)-r.due_days-1 当 trunc(o.customer_due_date) 为 null 然后 trunc (sysdate) + 60 else trunc(o.customer_due_date) - r.due_days end ),'yyyy-mm-dd') Due_date 到 p_due_date 从 dept_test r, emp_test o where o.emp_id = 1;
  • @GoranStefanović - 这取决于。 “谁调用此程序”可能无法正确处理日期。在这种情况下我会做的仍然是编写“这个”过程来返回一个日期。然后我会再写一个程序将日期转换为字符串,并仅在需要时使用它(例如,为这些不灵活的调用者提供数据)。无论如何,我刚刚意识到这是我几天来一直在 OTN 上回避的同一个问题;我对这个线程的贡献已经结束。
【解决方案2】:

因为这一行:

 p_due_date := to_char(p_due_date,'yyyy-mm-dd');

你得到这个错误。

因为 p_due_date 是 date,而赋值产生 char

顺便说一句,第6行程序也有问题,因为r,due_days中的,

【讨论】:

    【解决方案3】:

    正如其他人所说的

    p_due_date := to_char(p_due_date,'yyyy-mm-dd');
    

    似乎是问题所在。如果您要做的是删除日期值的时间部分,我建议您使用

    p_due_date := TRUNC(p_due_date);
    

    改为。

    祝你好运。

    【讨论】:

    • p_due_date := TRUNC(p_due_date);也给出了同样的错误。
    【解决方案4】:

    正如 mathguy 在他的回答中所说,当NLS_DATE_FORMATNLS_TIME_FORMAT 等某些连接参数与数据库服务器不同时,可能会发生此问题。就我而言,我使用的是 Symfony 框架,它的参数与我的 Oracle 服务器不同。所以我必须编辑我的代码以在查询执行前后使用原始 SQL 更改会话:

    $conn = $this->getEntityManager()->getConnection();
    
    // Same parameters as DB server
    $sqlAlterSession = "ALTER SESSION SET NLS_TIME_FORMAT = 'HH24:MI:SSXFF' NLS_DATE_FORMAT = 'DD/MM/RR' NLS_TIMESTAMP_FORMAT = 'DD/MM/RR HH24:MI:SSXFF' NLS_TIMESTAMP_TZ_FORMAT = 'DD/MM/RR HH24:MI:SSXFF TZR'";
    $conn->executeUpdate($sqlAlterSession);
    
    // Execute your query
    $sql = '...';
    $conn->execute($sql);
    
    // Restore original Symfony parameters
    $sqlAlterSession = "ALTER SESSION SET NLS_TIME_FORMAT = 'HH24:MI:SS' NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS' NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS' NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS TZH:TZM'";
    $conn->executeUpdate($sqlAlterSession);
    

    所有数据库服务器的参数都是在this answer 之后检索到的,ALTER SESSION ... 语句中带有 every 参数。

    【讨论】:

      猜你喜欢
      • 2014-04-27
      • 1970-01-01
      • 2017-08-24
      • 2016-04-02
      • 2015-01-11
      • 2010-11-26
      • 2012-10-09
      相关资源
      最近更新 更多