具有列数细分和过滤的Oracle APEX报告

时间:2014-05-06 12:52:55

标签: sql plsql oracle11g oracle-apex

我正在处理以下Oracle APEX v4.2.2报告。它基本上要求:

  1. 所有部门的员工总数。
  2. 在不同地点可能存在相同的3个部门(A,B和C)
  3. 每个地点可能有相同的A,B和C部门,但有些可能只有A或A和B或所有三个部门。
  4. 还需要员工部门细分计数(如下所示)
  5. 报告下方的整体复选框系统,向用户显示报告中所有位置的不同部门列表,该列表将用作过滤器(示例如下所示)
  6. 示例报告可能如下所示:

    Location          Dept A.     Dept. B     Dept. C      Total Employees
    ----------------- ----------- ----------- ------------ ---------------
    Paris             5           10          3            18
    Rome              10          20          5            35
    London            40          -           30           70
    
    
    Filter Departments: [X]Dept. A  [X]Dept. B  []Dept. C     [Apply Filter button]
    

    因此,使用上面的报告示例并假设通过三个表的ID存在数据库结构/连接:

    location
    department
    employees
    

    a)我可以获得总体员工总数,但是如上所述,每个地点部门的员工部门细分计数也是最好的方法,如报告所示,即部门A = 5,部门B = 10和部门C = 3?

    b)使用上面提到的过滤功能,如果我检查部门A和部门B,然后按下"应用过滤器按钮",我需要使用基于新值的上述报告重新生成在部门检查,所以新报告现在看起来像这样:

    Location          Dept A.     Dept. B     Total Employees
    ----------------- ----------- ----------- ---------------
    Paris             5           10          15
    Rome              10          20          30
    London            40          -           40
    

2 个答案:

答案 0 :(得分:1)

请参阅Is the following query possible with SQL Pivot?

上的答案

以下是您可以在数据轮转并且列是动态时可以使用的设置。你无法逃避一些plsql。

样本表和数据:

CREATE TABLE DEMO_LOCATIONS ( 
  ID   NUMBER(10) 
, NAME VARCHAR2(20)
, CONSTRAINT LOCATION_PK PRIMARY KEY (ID) 
);
CREATE TABLE DEMO_DEPARTMENTS ( 
  ID          NUMBER(10)
, LOCATION_ID NUMBER(10)
, NAME        VARCHAR2(20)
, CONSTRAINT DEPARTMENT_PK PRIMARY KEY (ID)
, CONSTRAINT DEPT_LOC_FK FOREIGN KEY (LOCATION_ID) REFERENCES DEMO_LOCATIONS (ID)
);
CREATE TABLE DEMO_EMPLOYEES (
  ID            NUMBER(10)
, DEPARTMENT_ID NUMBER(10)
, NAME          VARCHAR2(20)
, CONSTRAINT EMPLOYEES_PK PRIMARY KEY (ID) 
, CONSTRAINT EMPL_DEPT_FK FOREIGN KEY (DEPARTMENT_ID) REFERENCES DEMO_DEPARTMENTS (ID)
);

DECLARE
  l_emp_id NUMBER := 0;
BEGIN
  INSERT INTO demo_locations (id, name) VALUES (1, 'Paris');
  INSERT INTO demo_locations (id, name) VALUES (2, 'Rome');
  INSERT INTO demo_locations (id, name) VALUES (3, 'London');
  INSERT INTO
  INSERT INTO demo_departments(id, location_id, name) VALUES (1, 1, 'A');
  INSERT INTO demo_departments(id, location_id, name) VALUES (2, 1, 'B');
  INSERT INTO demo_departments(id, location_id, name) VALUES (3, 1, 'C');

  INSERT INTO demo_departments(id, location_id, name) VALUES (4, 2, 'A');
  INSERT INTO demo_departments(id, location_id, name) VALUES (5, 2, 'B');
  INSERT INTO demo_departments(id, location_id, name) VALUES (6, 2, 'C');

  INSERT INTO demo_departments(id, location_id, name) VALUES (7, 3, 'A');
  INSERT INTO demo_departments(id, location_id, name) VALUES (8, 3, 'B');
  INSERT INTO demo_departments(id, location_id, name) VALUES (9, 3, 'C');

  FOR I IN 1..9 LOOP
    FOR J IN 1..FLOOR(DBMS_RANDOM.VALUE(1,10)) LOOP
      l_emp_id := l_emp_id + 1;
      INSERT INTO demo_employees (id, department_id, name) VALUES (l_emp_id, i, 'employee #'||j);
    END LOOP;
  END LOOP;
END;
/
COMMIT;

WITH pivot_src AS (
  SELECT l.name location_name, d.name department_name, count(*) amount_employees
    FROM demo_locations l
    JOIN demo_departments d
      ON d.location_id = l.id
    JOIN demo_employees e
      ON e.department_id = d.id
   GROUP BY l.name, d.name
)
SELECT *
  FROM pivot_src
 pivot ( sum(amount_employees) as all_emps for department_name in ('A' as "Department A", 'B' as "Department B", 'C' as "Department C") );

APEX

报告来源:

DECLARE
  l_pivot_cols VARCHAR2(4000);
  l_pivot_qry VARCHAR2(4000);
BEGIN
  IF NVL(:PX_DEPTA, 'N') = 'Y' THEN
    l_pivot_cols := l_pivot_cols || '''A'' as "Department A",';
  END IF;
  IF NVL(:PX_DEPTB, 'N') = 'Y' THEN
    l_pivot_cols := l_pivot_cols || '''B'' as "Department B",';
  END IF;
  IF NVL(:PX_DEPTC, 'N') = 'Y' THEN
    l_pivot_cols := l_pivot_cols || '''C'' as "Department C",';
  END IF;

  l_pivot_cols := RTRIM(l_pivot_cols, ',');

  l_pivot_qry := 
   ' WITH pivot_src AS ( '
|| '   SELECT l.name location_name, d.name department_name, count(*) amount_employees '
|| '     FROM demo_locations l '
|| '     JOIN demo_departments d '
|| '       ON d.location_id = l.id '
|| '     JOIN demo_employees e '
|| '       ON e.department_id = d.id '
|| '    GROUP BY l.name, d.name '
|| ' ) '
|| ' SELECT * '
|| '   FROM pivot_src '
|| '  pivot ( sum(amount_employees) as all_emps for department_name in ('||l_pivot_cols||') ); ';

  RETURN l_pivot_qry;
END;

报告属性> PLSQL标题

DECLARE
  l_cols VARCHAR2(4000);
BEGIN
  l_cols := 'Location:';

  IF :PX_DEPTA = 'Y' THEN
    l_cols := l_cols || 'Department A:';
  END IF;
  IF :PX_DEPTB = 'Y' THEN
    l_cols := l_cols || 'Department B:';
  END IF;
  IF :PX_DEPTC = 'Y' THEN
    l_cols := l_cols || 'Department C:';
  END IF;

  RETURN RTRIM(l_cols, ':');
END;

制作3个复选框,默认为Y,LOV:STATIC2:;Y。将项目添加到报告“要提交的页面项目”。创建一个动态操作,该操作将在更改项目时触发,并刷新报告。

what it looks like

答案 1 :(得分:0)

对于a部分,看起来像一个数据透视表是你最好的选择。这是一篇很好的文章:http://www.oracle-base.com/articles/11g/pivot-and-unpivot-operators-11gr1.php

对于b部分,这可能会变得棘手。您需要确保部门C员工不会显示在总结果中,您需要隐藏部门C列。

使用另一个复选框指定包含所有部门可能是一个不错的用户界面功能,您可以使用动态操作清除其他复选框时单击它。

为了确保部门C员工不会出现在总数中,您可以在WHERE子句中包含以下内容:

WHERE
 (
   (:PXX_DEPT_A_FILTER = 'Y' AND employee.department = 'A')
   OR 
   (:PXX_DEPT_B_FILTER = 'Y' AND employee.department = 'B')
   OR
   (:PXX_DEPT_C_FILTER = 'Y' AND employee.department = 'C')
   OR 
   :PXX_ALL_DEPTS_FILTER = 'Y'
 )
 AND
 ....

要隐藏列,请使每个列以要检查的相应过滤器为条件。

您可以使用动态操作和部分页面刷新来消除使用“过滤器”按钮。