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')
我没有收到有效的月份错误。 知道如何解决这个问题吗? 感谢
答案 0 :(得分:2)
您的过程采用timestamp
类型的参数。您实际上是在通话中传递varchar2
类型的参数。这迫使Oracle使用您的会话varchar2
执行timestamp
参数到NLS_TIMESTAMP_FORMAT
的隐式转换。对于不同的会话,这可能会有所不同,因此至少某些会话可能会出错,因为该字符串与该会话NLS_TIMESTAMP_FORMAT
的格式不匹配。通过显式调用to_timestamp
或传递时间戳文字,可以更好地传递实际时间戳。
然后,您的过程将获取timestamp
个参数并将其传递给to_date
函数。 to_date
函数不接受timestamp
类型的参数,只接受varchar2
类型的参数。这迫使Oracle再次使用会话的timestamp
将varchar2
参数隐式转换为NLS_TIMESTAMP_FORMAT
。如果会话的NLS_TIMESTAMP_FORMAT
与to_date
调用中的显式格式掩码不匹配,则会出现错误,或者转换将返回您不期望的结果。
如果表格中的列实际上属于date
类型,则可以直接将date
与timestamp
进行比较。因此,似乎没有任何理由在此处致电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' ) );
这应该摆脱目前正在发生的所有隐式类型转换。