Question

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

My script runs between a range of dates. The two dates are IN parameters.

When I execute the procedure

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

I am getting not a valid month error. Any idea how to fix this? Thanks

Was it helpful?

Solution

Your procedure takes parameters of type timestamp. You're actually passing parameters of type varchar2 in your call. That forces Oracle to perform implicit conversion of the varchar2 parameters to timestamp using your session's NLS_TIMESTAMP_FORMAT. That will likely be different for different sessions so it is likely that at least some sessions will get an error because the string doesn't match the format of that session's NLS_TIMESTAMP_FORMAT. You'd be much better served passing in an actual timestamp either by explicitly calling to_timestamp or by passing a timestamp literal.

Your procedure then takes the timestamp parameters and pass them to the to_date function. The to_date function does not take parameters of type timestamp, it only takes parameters of type varchar2. That forces Oracle to do another implicit conversion of the timestamp parameters to varchar2, again using the session's NLS_TIMESTAMP_FORMAT. If the session's NLS_TIMESTAMP_FORMAT doesn't match the explicit format mask in your to_date call, you'll get an error or the conversion will return a result that you don't expect.

If the column in your table is actually of type date, you can directly compare a date to a timestamp. So there doesn't appear to be any reason to call to_date here. Based on your sample data, though, it appears that the column in your table is actually of type timestamp rather than date as your code implies, since a date does not have fractional seconds of precision. If that's the case, it makes even less sense to call to_date in your SELECT statement since your parameters are actually of type timestamp and your column is of type timestamp. Just compare the timestamp values.

My guess, therefore, is that you want something like

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;

and that you want to cal the procedure by passing actual timestamps. Using timestamp literals

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

or by explicitly calling 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' ) );

That should get rid of all the implicit type conversions that are currently taking place.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top