Home > Software engineering >  Random TIMESTAMP out of range
Random TIMESTAMP out of range

Time:01-28

I'm trying to create a function, which returns a random TIMESTAMP between a range of timestamps.

It doesn't appear to be working ALL the time as sometimes I get a value back before the starting range and sometimes I get a value back after the ending range.

Below is my test CASE and example of a TIMESTAMP out of range.In this example the TIMESTAMP is after the ending range of TIMESTAMP '2023-01-25 12:00:00'

Can someone please explain what the problem is and show me how to fix it as I can't seem to figure this out.


ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'DD-MON-YYYY  HH24:MI:SS.FF';

CREATE OR REPLACE FUNCTION random_timestamp(
      p_from      IN TIMESTAMP,
      p_to        IN TIMESTAMP,
      p_fraction  IN VARCHAR2   DEFAULT 'Y'
    ) RETURN TIMESTAMP
   IS
      return_val_y TIMESTAMP     := p_from   dbms_random.value () * (p_to - p_from   INTERVAL '1' DAY);
      return_val_n TIMESTAMP (0) := return_val_y;
 BEGIN
      RETURN  CASE
                  WHEN UPPER (SUBSTR (p_fraction, 1, 1)) = 'Y'
          THEN return_val_y
          ELSE return_val_N
          END;
END random_timestamp;
/

SELECT random_timestamp( 
TIMESTAMP '2023-01-25 09:00:00', TIMESTAMP '2023-01-25 12:00:00') as ts from dual

TS
26-JAN-2023  03:59:06.013730

CodePudding user response:

You are adding 1 day:

p_from   dbms_random.value () * (p_to - p_from   INTERVAL '1' DAY);

It falls within the range of p_from to p_to plus 1 day and is doing exactly what you told it to do.

If you don't want the range to be 1 day extra then remove INTERVAL '1' DAY

CREATE OR REPLACE FUNCTION random_timestamp(
  p_from      IN TIMESTAMP,
  p_to        IN TIMESTAMP,
  p_fraction  IN VARCHAR2   DEFAULT 'Y'
) RETURN TIMESTAMP
IS
  return_val_y TIMESTAMP(9) := p_from   dbms_random.value() * (p_to - p_from);
  return_val_n TIMESTAMP(0) := return_val_y;
BEGIN
  RETURN CASE
         WHEN p_fraction LIKE 'Y%' OR p_fraction LIKE 'y%'
         THEN return_val_y
         ELSE return_val_n
         END;
END random_timestamp;
/

Then:

SELECT MIN(ts),
       MAX(ts)
FROM   (
  SELECT random_timestamp(
           TIMESTAMP '2023-01-25 09:00:00',
           TIMESTAMP '2023-01-25 12:00:00'
         ) AS ts
  FROM   DUAL
  CONNECT BY LEVEL <= 1e6
);

May randomly output:

MIN(TS) MAX(TS)
25-JAN-23 09.00.00.017186000 25-JAN-23 11.59.59.999534000

And stays within the range.

fiddle

  • Related