create or replace package body my_calendar_pkg as function get_key_colour(p_key_code in varchar2, p_key_sql in varchar2) return varchar2 as TYPE t_key IS RECORD( key_code varchar2(20), key_name varchar2(200), key_colour varchar2(20) ); lv_key t_key; TYPE t_cursor IS REF CURSOR; lv_cursor t_cursor; lv_key_sql varchar2(2000); lv_index number; lv_colour varchar2(20); begin if p_key_code is not null then lv_key_sql := 'select * from (' || p_key_sql || ') the_key'; begin -- Open cursor OPEN lv_cursor FOR lv_key_sql; lv_index := 0; -- Fetch rows from result set one at a time: LOOP FETCH lv_cursor INTO lv_key; EXIT WHEN lv_cursor%NOTFOUND; lv_index := lv_index + 1; if lv_key.key_code = p_key_code then -- found a match! if lv_key.key_colour is not null then return lv_key.key_colour; else -- choose colour by index case lv_index when 1 then return 'FF0000'; when 2 then return '00FF00'; when 3 then return '0000FF'; when 4 then return '999900'; when 5 then return '009999'; when 6 then return '990099'; else return '000000'; end case; end if; end if; END LOOP; exception when others then return '00CC00'; end; return '0000CC'; end if; return 'FF0000'; end; procedure show ( p_start_date in date, p_end_date in date, p_time_scale in varchar2, p_data_sql in varchar2, p_key_sql in varchar2 ) as TYPE t_data IS RECORD( row_title varchar2(200), start_date date, end_date date, key_code varchar2(20), description varchar2(2000) ); lv_data t_data; TYPE t_key IS RECORD( key_code varchar2(20), key_name varchar2(200), key_colour varchar2(20) ); lv_key t_key; TYPE t_cursor IS REF CURSOR; lv_cursor t_cursor; lv_period date; lv_heading varchar2(50); lv_start_date date; lv_end_date date; lv_period_end date; lv_data_sql varchar2(2000); lv_key_sql varchar2(2000); lv_row_title varchar2(200); begin --htp.p('Start Date is ' || to_date(p_start_date)); --htp.p('Time scale is ' || p_time_scale); --htp.p('Data sql is ' || p_data_sql); --htp.p('Key sql is ' || p_key_sql); lv_start_date := nvl(p_start_date, sysdate); lv_end_date := nvl(p_end_date, lv_start_date + 28); htp.p(''); -- do table headings htp.p(''); lv_period := lv_start_date; loop if p_time_scale is null or substr(p_time_scale,1,1) = 'D' then if to_char(lv_period, 'D') in ('6','7') then htp.p(''); lv_period := lv_period + 1; end if; if substr(p_time_scale,1,1) = 'W' then htp.p(''); lv_period := lv_period + 7; end if; if substr(p_time_scale,1,1) = 'M' then htp.p(''); lv_period := add_months(lv_period,1); end if; if substr(p_time_scale,1,1) = 'Q' then htp.p(''); lv_period := add_months(lv_period,3); end if; if substr(p_time_scale,1,1) = 'Y' then htp.p(''); lv_period := add_months(lv_period,12); end if; --htp.p(''); exit when lv_period > lv_end_date; end loop; htp.p(''); -- now do the table data lv_data_sql := 'select * from (' || p_data_sql || ') the_data where end_date > :v_start_date and start_date < :v_end_date'; --htp.p('lv_data_sql: ' || lv_data_sql); lv_row_title := ''; lv_period := lv_start_date; -- Open cursor OPEN lv_cursor FOR lv_data_sql || ' order by row_title, start_date' USING lv_start_date, lv_end_date; -- Fetch rows from result set one at a time: LOOP FETCH lv_cursor INTO lv_data; EXIT WHEN lv_cursor%NOTFOUND; --htp.p(''); --lv_period := lv_start_date; if upper(lv_data.row_title) != upper(lv_row_title) then -- change in row -- this is the start of a new row lv_row_title := lv_data.row_title; --htp.p('New title'); -- finish off the old row if trunc(lv_period) > trunc(lv_start_date) then if lv_period <= lv_end_date then loop if p_time_scale is null or substr(p_time_scale,1,1) = 'D' then if to_char(lv_period, 'D') in ('6','7') then htp.p(''); lv_period := lv_period + 1; end if; if substr(p_time_scale,1,1) = 'W' then htp.p(''); lv_period := lv_period + 7; end if; if substr(p_time_scale,1,1) = 'M' then htp.p(''); lv_period := add_months(lv_period,1); end if; if substr(p_time_scale,1,1) = 'Q' then htp.p(''); lv_period := add_months(lv_period,3); end if; if substr(p_time_scale,1,1) = 'Y' then htp.p(''); lv_period := add_months(lv_period,12); end if; --htp.p(''); exit when lv_period > lv_end_date; end loop; end if; htp.p(''); end if; -- now start the new row htp.p(''); lv_period := lv_start_date; else -- end of change in row if lv_row_title is null then -- first row htp.p(''); lv_row_title := lv_data.row_title; lv_period := lv_start_date; end if; -- end of first row end if; if lv_period <= lv_data.end_date then -- the selected item is not finished - we need to display it... loop -- calculate when this period ends if p_time_scale is null or substr(p_time_scale,1,1) = 'D' then lv_period_end := lv_period + 1; end if; if substr(p_time_scale,1,1) = 'W' then lv_period_end := lv_period + 7; end if; if substr(p_time_scale,1,1) = 'M' then lv_period_end := add_months(lv_period,1); end if; if substr(p_time_scale,1,1) = 'Q' then lv_period_end := add_months(lv_period,3); end if; if substr(p_time_scale,1,1) = 'Y' then lv_period_end := add_months(lv_period,12); end if; if lv_data.start_date > lv_period_end then -- the current item starts after this peiod ends, so nothing to show if (p_time_scale is null or substr(p_time_scale,1,1) = 'D') and to_char(lv_period, 'D') in ('6','7') then htp.p(''); else htp.p(''); end if; else -- the current item has started (although it might have finished) if lv_data.end_date > lv_period or lv_period > lv_end_date then -- it hasn't ended yet, so it must still be going on if (p_time_scale is null or substr(p_time_scale,1,1) = 'D') and to_char(lv_period, 'D') in ('6','7') then htp.p(''); else htp.p(''); end if; else -- it has ended, so nothing more to do exit when true; end if; end if; -- moving right along... lv_period := lv_period_end; end loop; end if; END LOOP; -- Close cursor: CLOSE lv_cursor; -- fill in any remaining cells if lv_period < lv_end_date then loop if (p_time_scale is null or substr(p_time_scale,1,1) = 'D') and to_char(lv_period, 'D') in ('6','7') then htp.p(''); if p_time_scale is null or substr(p_time_scale,1,1) = 'D' then lv_period := lv_period + 1; end if; if substr(p_time_scale,1,1) = 'W' then lv_period := lv_period + 7; end if; if substr(p_time_scale,1,1) = 'M' then lv_period := add_months(lv_period,1); end if; if substr(p_time_scale,1,1) = 'Q' then lv_period := add_months(lv_period,3); end if; if substr(p_time_scale,1,1) = 'Y' then lv_period := add_months(lv_period,12); end if; exit when lv_period > lv_end_date; end loop; end if; htp.p('
 '); else htp.p(''); end if; htp.p( to_char(lv_period, 'DD') || '' || to_char(lv_period, 'DD/MM') || '' || to_char(lv_period, 'MON YYYY') || 'Q' || to_char(mod(to_number(to_char(lv_period, 'Q'))+2,4)+1) || ' ' || to_char(add_months(lv_period,-3),'YYYY') || '/' || to_char(add_months(lv_period,9),'YYYY') || '' || to_char(add_months(lv_period,-3),'YYYY') || '/' || to_char(add_months(lv_period,9),'YYYY') || '' || lv_period || '
' || nvl(lv_data.row_title, ' ') || lv_row_title || ''); else htp.p(''); end if; htp.p( '     ' || lv_period || '
' || nvl(lv_data.row_title, ' ') || '
' || nvl(lv_data.row_title, ' ') || '    '); else htp.p(''); end if; htp.p( ' 
'); end show; procedure show_key ( p_key_sql in varchar2 ) as TYPE t_key IS RECORD( key_code varchar2(20), key_name varchar2(200), key_colour varchar2(20) ); lv_key t_key; TYPE t_cursor IS REF CURSOR; lv_cursor t_cursor; lv_key_sql varchar2(2000); lv_index number; lv_colour varchar2(20); begin lv_key_sql := 'select * from (' || p_key_sql || ') the_key'; htp.p(''); -- Open cursor OPEN lv_cursor FOR lv_key_sql; lv_index := 0; -- Fetch rows from result set one at a time: LOOP FETCH lv_cursor INTO lv_key; EXIT WHEN lv_cursor%NOTFOUND; lv_index := lv_index + 1; if lv_key.key_colour is not null then lv_colour := lv_key.key_colour; else -- choose colour by index case lv_index when 1 then lv_colour := 'FF0000'; when 2 then lv_colour := '00FF00'; when 3 then lv_colour := '0000FF'; when 4 then lv_colour := '999900'; when 5 then lv_colour := '009999'; when 6 then lv_colour := '990099'; else lv_colour := '000000'; end case; end if; htp.p(''); END LOOP; htp.p('
 Key
 ' || lv_key.key_name || '
'); exception when others then null; end; end my_calendar_pkg;