pivot

How to use PIVOT XML and subquery with Oracle SQL


I'm using Oracle 21C. I have a query that select from 3 tables and works fine with "hard-coded" dates.

Select * from 
(   Select
      vc.last_name
    , vc.first_name  
    , va.attendance_type
    , ve.event_date 
    From
      VOL_CONTACT vc
    , VOL_ATTENDANCE va
    , VOL_EVENT ve
    Where
      va.contact_fkey = vc.prim_key
    And va.event_fkey = ve.prim_key
)
    pivot
    ( max(attendance_type)
      for event_date in ('30-mar-2023','18-apr-2023')
    )

However, The dates need to be dynamic. I tried to use PIVOT XML with a sub-query. The last four lines were changed to:

pivot xml
( max(attendance_type)
 for event_date in (select distinct to_char(event_date, 'dd-mon-yy') from vol_event)
)

. They show the LAST_NAME and FIRST_NAME values fine. However the column heading of the third column is "EVENT_DATE_XML" and the value of that column for every row is "(XMLTYPE)". How do I make PIVOT XML work with a sub-query?


Solution

  • Based on input from a more experienced developer, I went with another approach. Using an Apex Standard Report, I used the following for the report Region/Source (Type=Function Body Returning PL/SQL)

    declare
        l_pivot_cols varchar2(4000);
        l_sql        clob := q'{
    select
        *
    from
        (select
            vc.last_name
          , va.attendance_type
          , ve.event_date
        from
            vol_attendance va
                full outer join vol_event ve
                  on va.event_fkey = ve.prim_key
                full outer join vol_contact vc
                  on va.contact_fkey = vc.prim_key
                full outer join vol_contact_ministry vcm
                  on vcm.contact_fkey = vc.prim_key
                full outer join vol_ministry vm
                  on vm.prim_key = vcm.ministry_fkey
        where
            vm.ministry = 'Refugee'
        and vc.status = 'Active'
        )
    pivot (
        max(attendance_type) for event_date in (%s))
    order by
        last_name
    }';
    
    begin
        select
          listagg(apex_string.format('date ''%0'' "%0"', to_char(event_date, 'YYYY-MM-DD')), ', ') 
            within group (order by event_date)
        into
          l_pivot_cols
        from
          vol_event;
        return apex_string.format(l_sql, l_pivot_cols);
    end;
    

    Then, for the Attributes/Heading (Type=PL/SQL Function Body) I used:

    declare
      l_cols varchar2(4000);
    
    begin
      select
          listagg(to_char(event_date, 'Mon-dd-yy'), ':') within group (order by event_date)
      into
          l_cols
      from
          vol_event
    ;
      return 'Last Name:' || l_cols;
    end;
    

    That worked out well.