使用日期值执行IN参数过程时,这不是有效月份

时间:2014-05-07 17:32:39

标签: oracle plsql procedure

CREATE OR REPLACE PROCEDURE PROC1(
   V_STARTTIME    IN TIMESTAMP ,
   V_ENDTIME      IN TIMESTAMP )
BEGIN
INSERT INTO TAB1
SELECT COINS FROM TAB2
WHERE DATE BETWEEN TO_DATE(V_STARTTIME,'mm/dd/yyyy hh:mi:ss aM') AND TO_DATE(V_ENDTIME    ,'mm/dd/yyyy hh:mi:ss aM');
END;

SAMPLE DATE in Tab2 5/5/2014 9:46:38.000000 AM

我的脚本在一系列日期之间运行。这两个日期是IN参数。

执行程序时

执行proc1('5/05/2014 11:25:00 AM','5/05/2014 12:25:00 PM')

我没有收到有效的月份错误。 知道如何解决这个问题吗? 感谢

1 个答案:

答案 0 :(得分:2)

您的过程采用timestamp类型的参数。您实际上是在通话中传递varchar2类型的参数。这迫使Oracle使用您的会话varchar2执行timestamp参数到NLS_TIMESTAMP_FORMAT的隐式转换。对于不同的会话,这可能会有所不同,因此至少某些会话可能会出错,因为该字符串与该会话NLS_TIMESTAMP_FORMAT的格式不匹配。通过显式调用to_timestamp或传递时间戳文字,可以更好地传递实际时间戳。

然后,您的过程将获取timestamp个参数并将其传递给to_date函数。 to_date函数不接受timestamp类型的参数,只接受varchar2类型的参数。这迫使Oracle再次使用会话的timestampvarchar2参数隐式转换为NLS_TIMESTAMP_FORMAT。如果会话的NLS_TIMESTAMP_FORMATto_date调用中的显式格式掩码不匹配,则会出现错误,或者转换将返回您不期望的结果。

如果表格中的列实际上属于date类型,则可以直接将datetimestamp进行比较。因此,似乎没有任何理由在此处致电to_date。但是,根据您的示例数据,您的表中的列似乎实际上是timestamp类型,而不是代码所暗示的date,因为date没有小数秒精确。如果是这种情况,则在to_date语句中调用SELECT更不合理,因为您的参数实际上属于timestamp类型且您的列属于timestamp类型。只需比较timestamp值。

因此,我的猜测是你想要像

这样的东西
CREATE OR REPLACE PROCEDURE PROC1(
   V_STARTTIME    IN TIMESTAMP ,
   V_ENDTIME      IN TIMESTAMP )
BEGIN
  INSERT INTO TAB1( <<column name>> )
    SELECT COINS 
      FROM TAB2
     WHERE <<timestamp column name>> BETWEEN v_starttime AND v_endtime;
END;

并且您希望通过传递实际时间戳来调用该过程。使用时间戳文字

Execute proc1(timestamp '2014-05-05 11:25:00', timestamp '2014-05-05 12:25:00' )

或明确调用to_timestamp

execute proc1( to_timestamp( '5/05/2014 11:25:00 AM', 'MM/DD/YYYY HH:MI:SS AM' ),
               to_timestamp( '5/05/2014 12:25:00 PM', 'MM/DD/YYYY HH:MI:SS AM' ) );

这应该摆脱目前正在发生的所有隐式类型转换。