Dynamische Reporterzeugung mit APEX

04.
April
2008
Veröffentlicht von: Bernhard Koch

Hatten Sie schon einmal die Aufgabe dynamisch Reports mit APEX zu erzeugen? Es kann erst zur Laufzeit festgestellt werden wie viele Reporte pro Region dargestellt werden müssen.

In diesem Tipp erfahren Sie anhand der Tabellen des User Scott, unter Verwendung des htp Packages, wie sich mehrere Reports innerhalb einer Region aufbauen lassen.

Hatten Sie schon einmal die Aufgabe dynamisch Reports mit APEX zu erzeugen? Es kann erst zur Laufzeit festgestellt werden wie viele Reporte pro Region dargestellt werden müssen.

In diesem Tipp erfahren Sie anhand der Tabellen des User Scott, unter Verwendung des htp Packages, wie sich mehrere Reports innerhalb einer Region aufbauen lassen.

Es wird ein Report pro Abteilung der DEPT-Tabelle erzeugt. Jeder Report enthält den Abteilungsnamen, den Standort und die Anzahl der Mitarbeiter in der Kopfzeile. Als Inhalt werden die Mitarbeiternummer, Name und Job der Mitarbeiter der jeweiligen Abteilung ausgegeben.

Um die Reports zu befüllen müssen im Datenbankschema des Users Objekt Typen, Nested Tables und eine Funktion angelegt werden.

CREATE OR REPLACE TYPE SCOTT.OT_EMP AS OBJECT
( empno number,
  ename varchar2(20),
  job varchar2(20))
/

CREATE OR REPLACE TYPE SCOTT.OTT_EMP AS TABLE OF OT_EMP
/

CREATE OR REPLACE TYPE SCOTT.OT_DEPT AS OBJECT
°( dname varchar2(20),
  loc varchar2(20),
  COUNT_EMPS NUMBER,
  EMPS OTT_EMP)
/

CREATE OR REPLACE TYPE SCOTT.OTT_DEPT AS TABLE OF OT_DEPT
/

CREATE OR REPLACE FUNCTION get_Departments RETURN ott_dept IS
   TYPE v_department_name IS TABLE OF dept.dname%TYPE;
   TYPE v_department_loc IS TABLE OF dept.loc%TYPE;
   TYPE v_department_no IS TABLE OF dept.deptno%TYPE;
   TYPE v_employee_empno IS TABLE OF emp.empno%TYPE;
   TYPE v_employee_ename IS TABLE OF emp.ename%TYPE;
   TYPE v_employee_job IS TABLE OF emp.job%TYPE;
   v_deptno v_department_no;
   v_dname  v_department_name;
   v_loc    v_department_loc;
   v_empno  v_employee_empno;
   v_ename  v_employee_ename;
   v_job    v_employee_job;
   v_ot_dept  ot_dept;
   v_ot_emp   ot_emp;
   v_ott_dept ott_dept := ott_dept();
   v_ott_emp  ott_emp := ott_emp();
BEGIN
   -- Der Select für die Collection vom Typ OTT_DEPT
   SELECT deptno, dname, loc BULK COLLECT
   INTO   v_deptno, v_dname, v_loc
   FROM   dept;
   -- Objekte werden einmal initialisiert
   v_ot_dept := ot_dept(NULL, NULL, NULL, NULL);
   v_ot_emp  := ot_emp(NULL, NULL, NULL);
   FOR i IN 1 .. v_deptno.COUNT LOOP
      -- Der Objekttyp wird befüllt
      v_ot_dept.dname := v_dname(i);
      v_ot_dept.loc   := v_loc(i);
      -- Der Select für den Typ OTT_EMP
      SELECT empno, ename, job BULK COLLECT
      INTO   v_empno, v_ename, v_job
      FROM   emp
      WHERE  deptno = v_deptno(i);
      FOR x IN 1 .. v_empno.COUNT LOOP
         -- Das Subset wird befüllt
         v_ot_Emp.empno  := v_empno(x);
         v_ot_emp.ename := v_ename(x);
         v_ot_emp.job := v_job(x);
         v_ot_dept.count_emps := x;
         -- Die Collection (Subset) wird erweitert und geschrieben
         v_ott_emp.EXTEND();
         v_ott_emp(x) := v_ot_emp;
      END LOOP;
      v_ot_dept.EMPS := v_ott_emp;
      -- Die Collection wird erweitert und geschrieben
      v_ott_dept.EXTEND();
      v_ott_dept(i) := v_ot_dept;
      v_ot_dept.COUNT_EMPS := 0;
   END LOOP;
   RETURN v_ott_dept;
END get_Departments;
/

Die Nested Table vom Typ OT_EMP enthält die Mitarbeiter der jeweiligen Abteilung. Die Nested Table vom Typ OT_DEPT enthält pro Datensatz die Überschriften je eines Reports und das Subset OTT_EMP.

Innerhalb der Funktion wird die Nested Table OTT_DEPT befüllt. Das geschieht über zwei Schleifen. Die äußere Schleife füllt OTT_DEPT. Für jeden Eintrag in der Collection wird eine innere Schleife gestartet, welche das Subset OTT_EMP befüllt.


Kommen wir nun zum APEX Teil.

Zur Darstellung des Reports wählen wir eine Seite mit einer Region vom Typ "PL/SQL Dynamic Content". Auf dieser Seite wird folgender Code eingebunden.

DECLARE
   v_ott_emp ott_emp;
   v_ott_dept ott_dept;
   v_dat_style varchar2(100):='class="t12data"';
   v_tab_style varchar2(100):='class="t12standardalternatingrowcolors"';
   v_thead_style varchar2(100):='class="t12header"';

BEGIN
   v_ott_dept := get_Departments;
   IF v_ott_dept.COUNT > 0 THEN
    FOR i IN v_ott_dept.FIRST .. v_ott_dept.LAST LOOP
     htp.tableOpen(0,'top',0,0,v_tab_style);
     htp.tableRowOpen;
     htp.tableHeader(v_ott_dept(i).dname, 'top', 0, 0, 0,      0,v_thead_style);
     htp.tableHeader(v_ott_dept(i).loc, 'top', 0, 0, 0, 0,v_thead_style);
     htp.tableHeader(v_ott_dept(i).COUNT_EMPS ||' Mitarbeiter', 'top', 0,      0, 0, 0,v_thead_style);
     htp.tableRowClose;
     v_ott_emp := v_ott_dept(i).emps;
     v_dat_style := 'class="t12data"';
     IF v_ott_emp.COUNT > 0 THEN
        FOR j IN v_ott_emp.FIRST .. v_ott_emp.LAST LOOP
        htp.tableRowOpen;
        htp.tableData(v_ott_emp(j).empno, 0, 0, 0, 0, 0, v_dat_style);
        htp.tableData(v_ott_emp(j).ename, 0, 0, 0, 0, 0, v_dat_style);
        htp.tableData(v_ott_emp(j).job, 0, 0, 0, 0, 0, v_dat_style);
        htp.tableRowClose;
        -- Wechselnde Farben des Reports einstellen
        if v_dat_style = 'class="t12data"' then
        v_dat_style := 'class="t12dataalt"';
        else
           v_dat_style := 'class="t12data"';
        end if;
        END LOOP;
     END IF;
     htp.tableClose;
     htp.br;
    END LOOP;
   END IF;
END;

Es wird das CSS, des für die Applikation gewählten Themes, verwendet. In diesem Beispiel das Theme 12 Version 2.0. Beim Aufruf des htp Packages, wird analog zu in APEX erzeugten Reports, die jeweilige Klasse des CSS mit angegeben, damit sich die Reports nicht voneinander unterscheiden.

Es wird wie beim Befüllen der Collections, mit zwei Schleifen gearbeitet. Die äußere Schleife legt zuerst die Tabelle an und trägt die Überschriften in die Tabelle ein. Die innere Schleife füllt die Zeilen des Reports. Am Ende der inneren Schleife wird auch das Erscheinungsbild der Zeilen umgestellt.

Das Ergebnis ist eine Region auf der so viele Reports erscheinen, wie es Abteilungen innerhalb der Tabellen gibt.

Jede Menge Know-how für Sie!

In unserer Know-How Datenbank finden Sie mehr als 300 ausführliche Beiträge zu den Oracle-Themen wie DBA, SQL, PL/SQL, APEX und vielem mehr.
Hier erhalten Sie Antworten auf Ihre Fragen.