在 Oracle APEX 交互式报表中更新与过滤器相关的页面项目

Posted

技术标签:

【中文标题】在 Oracle APEX 交互式报表中更新与过滤器相关的页面项目【英文标题】:Updating Page Items with Respect to Filters in Oracle APEX Interactive Report 【发布时间】:2015-04-13 20:00:36 【问题描述】:

我最近开始在我的 Oracle APEX 应用程序中使用交互式报表。以前,应用程序中的所有页面都使用经典报告。我的新页面中的交互式报表效果很好,但是现在,我想在同一页面上的交互式报表上方添加一个汇总框/表格,以显示交互式报表中某些列的总和值。换句话说,如果我的交互式报表显示 3 个不同的经理姓名、2 个不同的办公地点和 5 个不同的员工,我的摘要框将包含一行和三列,分别带有数字 3、2 和 5。

到目前为止,我通过将摘要框创建为经典报表来完成这项工作,该报表计算我的交互式报表从中提取的同一个表中每一列的不同值。当我尝试过滤我的交互式报告时出现问题。显然,经典报表不会根据交互式报表过滤器刷新,但我不知道如何将两者链接起来,以便经典报表响应交互式报表中的过滤器。根据我的研究,有一些方法可以使用 javascript/jquery 引用交互式报告搜索框中的值。如果可能,我想使用 javascript 或 jquery 引用交互式表的过滤器中的值,以便在每次应用新过滤器时刷新摘要框。有谁知道怎么做?

【问题讨论】:

别这样。诚实地。如果只是因为 apex 5 即将到来,那么您创建的所有内容都将过时。你为什么需要这个?这是某种要求吗?这可能不是您想要解决的方法,因为它会产生大量开销。 我的客户要求包含摘要。我能想到的唯一方法是通过页面顶部的单独经典报告。有没有办法在交互式报告中创建类似的摘要? 【参考方案1】:

不要对过滤器进行 javascript 解析。这是一个坏主意——想想你将如何实现它?有大量的编码需要完成,还有大量的 ajax。随着 apex 5 就在拐角处,当 API 和标记即将发生巨大变化时,它会给您带来什么?


也不要仅仅屈服于要求。首先确定它在技术上的可行性。如果不是,请确保您非常清楚地说明了时间消耗的含义。拥有这些不同的价值计数的真正价值是什么?也许还有另一种方法可以实现他们想要的?也许这只不过是一种尝试性的解决方案,而不是真正问题的核心。需要考虑的事情...


话虽如此,这里有两个选项:

第一种方法:计算交互式报表的不同聚合

您可以通过“操作”按钮将这些添加到 IR。

请注意,此聚合将是最后一行!在我在这里发布的示例中,将每页的行数减少到 5 会将聚合行推到分页集 3!


第二种方法:APEX_IR 和 DBMS_SQL

您可以使用 apex_ir API 检索 IR 的查询,然后使用它进行计数。(Apex 4.2) APEX_IR.GET_REPORT(Apex 5.0) APEX_IR.GET_REPORT

一些提示: 通过查询 apex_application_page_regions 检索区域 ID

确保您的源查询包含#...# 替换字符串。 (如#OWNER#。)

然后获取报表SQL,重写,执行。例如:

DECLARE
   l_report apex_ir.t_report;
   l_query varchar2(32767);

  l_statement varchar2(32000);
  l_cursor integer;
  l_rows number;
  l_deptno number;
  l_mgr number;
BEGIN 
    l_report := APEX_IR.GET_REPORT (
                    p_page_id => 30,
                    p_region_id => 63612660707108658284,
                    p_report_id => null);
    l_query := l_report.sql_query;
    sys.htp.prn('Statement = '||l_report.sql_query);
    for i in 1..l_report.binds.count
    loop
        sys.htp.prn(i||'. '||l_report.binds(i).name||' = '||l_report.binds(i).value);
    end loop;

    l_statement := 'select count (distinct deptno), count(distinct mgr) from ('||l_report.sql_query||')';

    sys.htp.prn('statement rewrite: '||l_statement);

 l_cursor := dbms_sql.open_cursor;
    dbms_sql.parse(l_cursor, l_statement, dbms_sql.native);

    for i in 1..l_report.binds.count
    loop
      dbms_sql.bind_variable(l_cursor, l_report.binds(i).name, l_report.binds(i).value);
    end loop;

    dbms_sql.define_column(l_cursor, 1, l_deptno);
    dbms_sql.define_column(l_cursor, 2, l_mgr);

    l_rows := dbms_sql.execute_and_fetch(l_cursor);

    dbms_sql.column_value(l_cursor, 1, l_deptno);
    dbms_sql.column_value(l_cursor, 2, l_mgr);

    dbms_sql.close_cursor(l_cursor);

    sys.htp.prn('Distinct deptno: '||l_deptno);
    sys.htp.prn('Distinct mgr: '||l_mgr);
  EXCEPTION WHEN OTHERS THEN
    IF DBMS_SQL.IS_OPEN(l_cursor) THEN
      DBMS_SQL.CLOSE_CURSOR(l_cursor);
    END IF;
    RAISE;
END;

我将 apex_ir.get_report 和 dbms_sql 中的示例代码放在一起。Oracle 11gR2 DBMS_SQL reference

但有一些严重的警告:列列表很棘手。如果用户可以控制所有列并且可以删除一些列,那么这些列将从选择列表中消失。例如,在我的示例中,让用户隐藏 DEPTNO 列会使整个代码崩溃,因为即使它会从内部查询中消失,我仍然会对该列进行计数。您可以通过不让用户控制它来阻止它,或者首先解析语句等...


祝你好运。

【讨论】:

谢谢,第二种方法效果很好! APEX_IR 或 DBMS_SQL 包非常棒!我使用 APEX 页面项目将结果打印到页面上。我会将它们格式化为一个摘要框。我还尝试将代码放入经典报告的源代码中。我使用 l_statement 字符串作为返回字符串,但每次我尝试保存报告时,APEX_IR.GET_REPORT 查询都会在工作区执行并生成一条错误消息,告诉我在 Application 4000 的该页面上找不到报告 ID (我的工作区应用程序 ID)。你以前遇到过这种情况吗? 您的意思是保存报告时出现错误?还是在执行时? @jobrien9 对,试过之后我明白了。 Apex 将运行代码以尝试解析语句并确定列。显然这失败了。该语句应该只在运行时运行,就像 PLSQL 进程一样。为此,您需要将Use generic column names 属性设置为yes,因为这将告诉apex 仅在运行时解析语句。缺点是您将只有“通用”列名 (COL1, COL2, COL3,...),尽管您仍然可以控制列标题。然而。即使它会验证,在运行时它仍然无法工作! @jobrien9 但是 - 如果您真的有兴趣在报告区域中执行此操作,您可以查看流水线函数,简而言之,它是一个“流式传输”行的函数,您可以从中选择。在那里您可以编写 plsql 代码来解析和执行语句,例如在流程代码中,并将它们作为行返回。 好的,这是有道理的。由于我的报告足够小,我最终在“页面加载过程之前”执行代码。我将我感兴趣的每个输出值保存到隐藏的 APEX 项目,并让报告在其源代码中选择每个隐藏的 APEX 项目。

以上是关于在 Oracle APEX 交互式报表中更新与过滤器相关的页面项目的主要内容,如果未能解决你的问题,请参考以下文章

在交互式报表中创建列链接 -Oracle Apex

交互式报表 Oracle Apex 5 上的 LOV

如何在 Oracle APEX 交互式网格报表中维护正在运行的计数器

在 Oracle APEX 中访问报表输出表

无法使用 ORACLE APEX 删除交互式报表中的行

创建交互式报表时的 Oracle APEX ORA-01722