【问题标题】:Problem retrieving time from date field in oracle stored procedure从 oracle 存储过程中的日期字段检索时间的问题
【发布时间】:2010-02-02 17:22:02
【问题描述】:

我在从 SP 的日期字段中检索时间时遇到问题。如果我运行查询:

select TO_CHAR(HOR_HST_ATN,'YYYY/MM/DD HH24:MI:SS') AS HOR_HST_ATN FROM AAM0_DT_RSTCN ;

返回日期和时间ok。

但在SP中,代码:

SELECT   FEC_DSD_ATN, FEC_HST_ATN, NOM_SEM_DSD_ATN, NOM_SEM_HST_ATN, 
    TO_DATE(HOR_DSD_ATN ,'DD/MM/YYYY HH24:MI:SS') as  HOR_DSD_ATN,
    TO_DATE(HOR_HST_ATN,'DD/MM/YYYY HH24:MI:SS') as HOR_HST_ATN

只返回日期 ok 但时间是 00:00

如果我尝试在 SP 中使用 TO_CHAR 进行选择,如下所示:

SELECT   FEC_DSD_ATN, FEC_HST_ATN, NOM_SEM_DSD_ATN, NOM_SEM_HST_ATN,
 TO_CHAR(HOR_DSD_ATN ,'YYYY/MM/DD HH24:MI:SS') as  HOR_DSD_ATN,
 TO_CHAR(HOR_HST_ATN,'YYYY/MM/DD HH24:MI:SS') as HOR_HST_ATN

我收到错误:SQLCODE: -6502 SQLERRM: ORA-06502: PL/SQL: error ...

有什么线索吗?顺便说一句,我必须使用 SP 来检索此值。

更新:该列是日期类型。这是完整的 SP:

FUNCTION FN_AAM_EV_RSTCN ( 

I_NUM_CONTRATO            IN  AAM0_DT_RSTCN.NUM_CONTRATO%TYPE,
I_COD_PFL                  IN  AAM0_DT_RSTCN.COD_PFL%TYPE, 
I_COD_APL_PFM              IN  AAM0_DT_RSTCN.COD_APL_PFM%TYPE, 
I_COD_PTO                  IN  AAM0_DT_RSTCN.COD_PTO%TYPE, 
I_COD_FNC                  IN  AAM0_DT_RSTCN.COD_FNC%TYPE
) RETURN BOOLEAN
AS
T_FEC_DSD_ATN                   AAM0_DT_RSTCN.FEC_DSD_ATN%TYPE;
T_HOR_DSD_ATN                   AAM0_DT_RSTCN.HOR_DSD_ATN%TYPE;
T_FEC_HST_ATN                   AAM0_DT_RSTCN.FEC_HST_ATN%TYPE;
T_HOR_HST_ATN                   AAM0_DT_RSTCN.HOR_HST_ATN%TYPE;
T_NOM_SEM_DSD_ATN               AAM0_DT_RSTCN.NOM_SEM_DSD_ATN%TYPE;
T_NOM_SEM_HST_ATN               AAM0_DT_RSTCN.NOM_SEM_HST_ATN%TYPE;

 O_RESULTSET2          REST_REFCUR;

BEGIN
 OPEN O_RESULTSET2 FOR 

   SELECT   FEC_DSD_ATN, FEC_HST_ATN, NOM_SEM_DSD_ATN, NOM_SEM_HST_ATN, 
    TO_CHAR(HOR_DSD_ATN ,'DD/MM/YYYY HH24:MI:SS') as  HOR_DSD_ATN,
    TO_CHAR(HOR_HST_ATN,'DD/MM/YYYY HH24:MI:SS') as HOR_HST_ATN
    FROM    AAM0_DT_RSTCN
    WHERE ROWNUM <=1
    AND   NUM_CONTRATO          = NVL ( I_NUM_CONTRATO, NUM_CONTRATO )
    AND     COD_PFL               = NVL ( I_COD_PFL, COD_PFL )
    AND     COD_APL_PFM           = NVL ( I_COD_APL_PFM, COD_APL_PFM )
    AND     COD_PTO               = NVL ( I_COD_PTO, COD_PTO )
    AND     COD_FNC               = NVL ( I_COD_FNC, COD_FNC )    
    AND     FLG_RCS               = 'D'
    AND     COD_TPO_CDC           = 'PC'
    ;

   FETCH O_RESULTSET2 INTO T_FEC_DSD_ATN, T_FEC_HST_ATN, T_NOM_SEM_DSD_ATN, T_NOM_SEM_HST_ATN, T_HOR_DSD_ATN, T_HOR_HST_ATN ;

  IF (O_RESULTSET2%NOTFOUND) THEN
    RETURN TRUE;
  ELSE
   dbms_output.put_line('EVALUO RESTRICCIONES: T_FEC_DSD_ATN '  || T_FEC_DSD_ATN || ' T_FEC_HST_ATN : ' || T_FEC_HST_ATN || ' T_NOM_SEM_DSD_ATN: ' ||
                 T_NOM_SEM_DSD_ATN || ' T_NOM_SEM_HST_ATN: '  || T_NOM_SEM_HST_ATN || ' T_HOR_DSD_ATN: ' || TO_CHAR(T_HOR_DSD_ATN ,'DD/MM/YYYY HH24:MI:SS')  || 
                ' T_HOR_HST_ATN: ' || TO_CHAR(T_HOR_HST_ATN ,'DD/MM/YYYY HH24:MI:SS') );

     IF (NOT((T_FEC_DSD_ATN IS NULL) and (T_FEC_HST_ATN IS NULL)) ) THEN

       IF ( NOT ((T_FEC_DSD_ATN  <= SYSDATE) AND (T_FEC_HST_ATN >= SYSDATE ))) THEN
                RETURN FALSE;
        END IF ;

    END IF ;

  RETURN TRUE;

  END IF ;

EXCEPTION

  WHEN NO_DATA_FOUND THEN
    RETURN TRUE; 

  WHEN OTHERS THEN


    IF O_RESULTSET2%ISOPEN THEN

      CLOSE O_RESULTSET2;

    END IF;


    DBMS_OUTPUT.PUT_LINE('ERROR en FN_AAM_EV_RSTCN : '); 
    DBMS_OUTPUT.PUT_LINE('  SQLCODE: ' || SQLCODE );
    DBMS_OUTPUT.PUT_LINE('  SQLERRM: ' || SQLERRM );

    ROLLBACK;

 END FN_AAM_EV_RSTCN;

【问题讨论】:

  • “ORA-06502:PL/SQL:数字或值错误。您尝试执行导致算术、数字、字符串、转换或约束错误的语句。”存在不具有预期类型的​​列或变量。我们能看到完整的代码吗?
  • 什么是存储过程代码。该列是 DATE 还是 TIMESTAMP ?

标签: oracle stored-procedures


【解决方案1】:

您的问题在于以下代码:

...
T_HOR_DSD_ATN                   AAM0_DT_RSTCN.HOR_DSD_ATN%TYPE;
T_HOR_HST_ATN                   AAM0_DT_RSTCN.HOR_HST_ATN%TYPE;
...
SELECT   FEC_DSD_ATN, FEC_HST_ATN, NOM_SEM_DSD_ATN, NOM_SEM_HST_ATN, 
TO_CHAR(HOR_DSD_ATN ,'DD/MM/YYYY HH24:MI:SS') as  HOR_DSD_ATN,
TO_CHAR(HOR_HST_ATN,'DD/MM/YYYY HH24:MI:SS') as HOR_HST_ATN
FROM    AAM0_DT_RSTCN
...
FETCH O_RESULTSET2 INTO T_FEC_DSD_ATN, T_FEC_HST_ATN, T_NOM_SEM_DSD_ATN,
T_NOM_SEM_HST_ATN, T_HOR_DSD_ATN, T_HOR_HST_ATN ;

由于 HOR_DSD_ATNHOR_HST_ATN 列具有 DATE 数据类型,因此您的局部变量(T_HOR_DSD_ATNT_HOR_HST_ATN)也是 DATE。但是,在您的 SELECT 中,您使用 TO_CHAR 函数将这些日期转换为字符串。因此,您的 fetch 有效地做到了这一点(我在这里编了一些日期):

T_HOR_DSD_ATN := '03/02/2010 09:33:30';
T_HOR_HST_ATN := '01/01/2010 12:30:00';

由于您将字符串分配给日期变量,Oracle 必须执行隐式 TO_DATE - 因此它使用会话的 NLS_DATE_FORMAT 来转换它们,这可能只是获取日期部分(例如DD/MM/YYYY)并丢失时间值.

要修复它,只需从您的 SELECT 语句中删除 TO_CHAR() - 这样您就可以在本地变量中获得未经修改的日期 + 时间值。

【讨论】:

  • 像往常一样,隐式类型转换是邪恶的。不错的收获。
【解决方案2】:

由于 TO_DATE 函数将 VARCHAR 作为参数,因此您不会在 DATE 字段上使用此函数。如果您想从 DATE 字段中检索日期和时间,您只需选择没有函数的字段:

SELECT   FEC_DSD_ATN, FEC_HST_ATN, NOM_SEM_DSD_ATN, NOM_SEM_HST_ATN, 
         HOR_DSD_ATN, HOR_HST_ATN
   ...

更新

问题是您将 TO_CHAR(HOR_DSD_ATN, 'DD/MM/YYYY HH24:MI:SS') 提取到 DATE 字段中。有一个隐式转换会截断您的日期。对 DATE 变量使用 to_char,对 CHAR 变量使用 to_date

我的建议:

FUNCTION FN_AAM_EV_RSTCN(I_NUM_CONTRATO IN AAM0_DT_RSTCN.NUM_CONTRATO%TYPE,
                         I_COD_PFL      IN AAM0_DT_RSTCN.COD_PFL%TYPE,
                         I_COD_APL_PFM  IN AAM0_DT_RSTCN.COD_APL_PFM%TYPE,
                         I_COD_PTO      IN AAM0_DT_RSTCN.COD_PTO%TYPE,
                         I_COD_FNC      IN AAM0_DT_RSTCN.COD_FNC%TYPE) 
   RETURN BOOLEAN AS
BEGIN
   FOR cc IN (SELECT FEC_DSD_ATN, FEC_HST_ATN, NOM_SEM_DSD_ATN, 
                     NOM_SEM_HST_ATN, HOR_DSD_ATN, HOR_HST_ATN
                FROM AAM0_DT_RSTCN
               WHERE ROWNUM <= 1
                 AND NUM_CONTRATO = NVL(I_NUM_CONTRATO, NUM_CONTRATO)
                 AND COD_PFL = NVL(I_COD_PFL, COD_PFL)
                 AND COD_APL_PFM = NVL(I_COD_APL_PFM, COD_APL_PFM)
                 AND COD_PTO = NVL(I_COD_PTO, COD_PTO)
                 AND COD_FNC = NVL(I_COD_FNC, COD_FNC)
                 AND FLG_RCS = 'D'
                 AND COD_TPO_CDC = 'PC') LOOP
      dbms_output.put_line(' T_HOR_DSD_ATN: ' || 
                           TO_CHAR(cc.HOR_DSD_ATN, 'DD/MM/YYYY HH24:MI:SS') ||
                           ' T_HOR_HST_ATN: ' || 
                           TO_CHAR(cc.HOR_HST_ATN, 'DD/MM/YYYY HH24:MI:SS'));
      -- your logic with return boolean
   END LOOP;
   -- no rows found
   RETURN TRUE;
EXCEPTION
   WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE('ERROR en FN_AAM_EV_RSTCN : ');
      DBMS_OUTPUT.PUT_LINE('  SQLCODE: ' || SQLCODE);
      DBMS_OUTPUT.PUT_LINE('  SQLERRM: ' || SQLERRM);
      RAISE;
END FN_AAM_EV_RSTCN;

【讨论】:

  • 感谢您的回复,我们进行了建议的更改,但仍然返回 00:00。
【解决方案3】:

如果 HOR_HST_ATN 是日期列,则 TO_DATE(HOR_HST_ATN,'DD/MM/YYYY HH24:MI:SS') 必须是拼写错误。您的意思可能是 TO_CHAR()。

【讨论】:

  • 如果我尝试使用 TO_CHAR 会出现错误(请检查更新后的问题)
【解决方案4】:

如果列是由没有时间元素的日期填充的,Oracle 将时间默认为午夜...

SQL> create table t23 (d date)
  2  /

Table created.

SQL> insert into t23 values (sysdate)
  2  /

1 row created.

SQL> insert into t23 values (to_date('03-FEB-2010', 'DD-MON-YYYY'))
  2  /

1 row created.

SQL> select to_char(d, 'DD/MM/YYYY HH24:MI:SS') as datetime from t23
  2  /

DATETIME
-------------------
02/02/2010 17:59:51
03/02/2010 00:00:00

SQL>

【讨论】:

  • 如果我运行选择它会显示正确的时间;当我运行 SP 时,时间是 00:00
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-20
  • 2011-01-25
  • 1970-01-01
  • 2015-05-14
  • 1970-01-01
相关资源
最近更新 更多