Skip to Main Content

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Paul.

Asked: June 24, 2020 - 11:05 am UTC

Last updated: June 25, 2020 - 12:41 pm UTC

Version: 18

Viewed 1000+ times

You Asked

I am randomly generating rows for 3 tables. For the tour_detail table how can I find the MAX(tour_time) MMDDYYYY only add a day (keeping the HH24:MI:SS the same) and INSERT those values into the tour_detail table.

create table locations as
select level as location_id,
       'Door ' || level as location_name,
       case round(dbms_random.value(1,3)) 
            when 1 then 'A' 
            when 2 then 'T' 
            when 3 then 'G' 
       end as location_type
from   dual
connect by level <= 25;

alter table locations 
  add ( 
    constraint location_id_pk
    primary key (location_id)
  );

create table tour_hdr(
   tour_id NUMBER(4),
   tour_name VARCHAR2(20),
   active_days VARCHAR2(7)
);

insert into tour_hdr (tour_id, tour_name, active_days)
with loop1(tour_id) as (
  select level 
  from   dual connect by level <= 10
), loop2(b) as (select level from dual connect by level <= 7)
  SELECT tour_id,
         'Tour ' || tour_id AS tour_name,
         replace(listagg(CASE round(dbms_random.value(1,2))
                           WHEN 1 THEN 'Y'
                           WHEN 2 THEN 'N'
                          END,',')               within group (order by b)
                 ,',') AS active_days
  FROM  loop1
  cross join loop2
  group by tour_id;

alter table tour_hdr
  add ( 
    constraint tour_hdr_id_pk
    primary key (tour_id)
  );

create table tour_detail 
(
      tour_id NUMBER(4),
      tour_time DATE,
      location_id NUMBER(4)
);
  
alter table tour_detail 
  add ( 
    constraint tour_detail_fk
    foreign key (tour_id)
    references tour_hdr (tour_id)
  );

declare
    v_loc number;      
    v_prev_loc number := 0;
    v_dt date := trunc(sysdate);
    v_dt_save date := trunc(sysdate);
begin

  for trs in ( select tour_id from tour_hdr )
  loop
     -- for each  tour generate 15 to 25 rows
     for i in 1..dbms_random.value(15, 25) loop
     
       -- If date >23:45:00 reset.
       if v_dt > (v_dt_save + (1/1440*1425))
       then 
          -- reset time 
          v_dt :=  v_dt_save;
       else
          -- increase last used date by random 6 to 12 minutes
          v_dt := v_dt + dbms_random.value(6,12)/(24*60);
       end if;

       -- get random location
       select location_id 
       into   v_loc 
       from (select location_id from locations where location_type = 'G' order by dbms_random.value) 
       where rownum = 1;

       -- ensure same location_id isn't consecutive 
       if v_prev_loc != v_loc
       then
         insert into tour_detail (tour_id, tour_time, location_id)
         values (trs.tour_id, v_dt, v_loc);
         v_prev_loc := v_loc;
       end if;

    end loop;
  end loop;
end;
/


and Chris said...

I'm not sure exactly how/where you're trying to calculate this max.

To find the highest value in a column, all you need is the MAX function.

And remember: the unit of arithmetic in Oracle Database is the day. So add one to a date, and you'll get exactly the same time the next day:

select max ( tour_time ) mx, 
       max ( tour_time ) + 1 mx_next_day
from   tour_detail;

MX                     MX_NEXT_DAY            
24-JUN-2020 23:45:59   25-JUN-2020 23:45:59 

Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

A reader, June 24, 2020 - 2:04 pm UTC

Apologies for the ambiguity. As you can see below the MAX time for the group of records is 06252020. I want to SELECT ALL the records for that date, update the group by 1 day, INSERT them into the tour_detail table.

TOUR_ID    TOUR_TIME    LOCATION_ID
1    06242020 00:08:11    6
1    06242020 00:15:10    17
1    06242020 00:23:39    11

1    06252020 00:08:11    6
1    06252020 00:15:10    17
1    06252020 00:23:39 11   


Chris Saxon
June 25, 2020 - 12:41 pm UTC

If you want to find all the rows which have the same calendar date (ignoring time) as the max date in the table, you can do something like:

- Find the MAX data
- TRUNC() it to get start of the day
- Find all the rows greater than this value

For example:

with rws as (
  select t.*,
         max ( tour_time ) over () mx_dt
  from   tour_detail t
)
  select tour_time + 1
  from   rws
  where  tour_time > trunc ( mx_dt );

More to Explore

SQL

The Oracle documentation contains a complete SQL reference.