ZZa*_*ZZa 6 sql oracle plsql report oracle-apex
我需要使用Oracle Application Express框架完成此任务.
假设我们有这样一个问题:
select
col1,
col2,
val1,
val2,
val3,
val4,
val5,
val6,
val7,
val8,
val9,
val10,
val11
from table(mega_function(city => ?, format => ?, percent => ?, days => ?));
Run Code Online (Sandbox Code Playgroud)
此查询返回类似这样的内容(以CSV格式显示):
col1;col2;val1;val2;val3;val4;val5;val6;val7;val8;val9;val10;val11
S2;C1;32000;120;"15:38:28";1450;120;1500;1200;31000;120;32600;300
S1;C1;28700;120;"15:35:01";150;120;1500;1800;2700;60;28900;120
S1;C2;27000;240;"14:44:23";0;1500;240;1200;25500;60;null;null
Run Code Online (Sandbox Code Playgroud)
简单来说,查询基于流水线函数,该函数接受一些参数并返回前两列不同值对的一些值集col1;col2
.
我需要实现的是矩阵报告,其中值col1
用作报告的行和值的col2
列.在交叉点上有一些单元格,其中包含一对值的集合,并应用了一些格式和样式.还需要的是 - 按行排序(应按列"val1"的值对列进行排序).
所以问题是 - 使用一些交互和自定义样式实现这样的矩阵报告的最佳实践是什么?
我已经尝试过研究:
Use Generic Column Names
集的属性中Yes
(为了仅在运行时解析查询),对于报告的标题,我使用了另一个PL/SQL函数,以格式生成字符串heading1:headning2:...:headingN
.该解决方案有效(你可以在这里查看 - https://apex.oracle.com/pls/apex/f?p=132832:2),但是我需要每次动态刷新报告,比方说,5秒,它会在性能方面很糟糕(如果我们谈论执行计划,动态SQL总是很糟糕而且不可管理).此解决方案也不合适,因为标题与数据不一致(实际上我order by col1
在PL/SQL函数中的查询中使用以使标题位于其位置)并且我不知道如何在此处对行进行排序.不幸的是,由于报告的生存条件,我在问题中提到的选项都不满足所有要求:
我意识到,对于这样的任务,最好在客户端即时操作 DOM,而不是使用一些开箱即用的 APEX 解决方案,例如经典报告、交互式报告或网格。
我使用DataTables.js jQuery 插件来实现这种方法。经过一周的技术评估和学习一些基本的 JavaScript(这不是我的主要技能)后,我得到了以下结果:
在 APEX 应用程序中,我实现了一个 Ajax 回调进程(称为TEST_AJAX
),它运行 PL/SQL 代码,该代码将 JSON 对象返回到SYS.HTP
输出(使用APEX_JSON
或HTP
包)。其来源:
declare
l_temp sys_refcursor;
begin
open l_temp for go_pivot;
APEX_JSON.open_object;
APEX_JSON.open_array('columns');
APEX_JSON.open_object;
APEX_JSON.write('data', 'COL2');
APEX_JSON.write('title', '/');
APEX_JSON.close_object;
for x in (select distinct col1 from test order by 1) loop
APEX_JSON.open_object;
APEX_JSON.write('data', upper(x.col1));
APEX_JSON.write('title', x.col1);
APEX_JSON.close_object;
end loop;
APEX_JSON.close_array;
APEX_JSON.write('data', l_temp);
APEX_JSON.close_object;
end;
Run Code Online (Sandbox Code Playgroud)
函数go_pivot
源码:
create or replace function go_pivot return varchar2
is
l_query long := 'select col2';
begin
for x in (select distinct col1 from test order by col1)
loop
l_query := l_query ||
replace(', min(decode(col1,''$X$'',v)) $X$',
'$X$',
x.col1);
end loop;
l_query := l_query || ' from test group by col2';
return l_query;
end;
Run Code Online (Sandbox Code Playgroud)
然后我在页面上创建了一个静态内容区域,其来源如下:
declare
l_temp sys_refcursor;
begin
open l_temp for go_pivot;
APEX_JSON.open_object;
APEX_JSON.open_array('columns');
APEX_JSON.open_object;
APEX_JSON.write('data', 'COL2');
APEX_JSON.write('title', '/');
APEX_JSON.close_object;
for x in (select distinct col1 from test order by 1) loop
APEX_JSON.open_object;
APEX_JSON.write('data', upper(x.col1));
APEX_JSON.write('title', x.col1);
APEX_JSON.close_object;
end loop;
APEX_JSON.close_array;
APEX_JSON.write('data', l_temp);
APEX_JSON.close_object;
end;
Run Code Online (Sandbox Code Playgroud)
我将 DataTables.js 的 CSS 和 JS 文件上传到应用程序静态文件,并将它们包含在页面属性中。在JavaScript
页面的部分中Function and Global Variable Declaration
,我添加了以下 JavaScript 代码:
create or replace function go_pivot return varchar2
is
l_query long := 'select col2';
begin
for x in (select distinct col1 from test order by col1)
loop
l_query := l_query ||
replace(', min(decode(col1,''$X$'',v)) $X$',
'$X$',
x.col1);
end loop;
l_query := l_query || ' from test group by col2';
return l_query;
end;
Run Code Online (Sandbox Code Playgroud)
因为Execute when Page Loads
我补充道:
<div id="datatable_test_container"></div>
Run Code Online (Sandbox Code Playgroud)
这一切的作用是什么:
<div>
接收一个应用了 DataTables 构造函数的空表。因此,有一个完全交互式、动态刷新的报告,具有排序、分页、搜索、事件处理等选项。所有这些都是在客户端完成的,无需向服务器进行额外的查询。
您可以使用此实时演示检查结果 (顶部区域是 DataTables 报告,其下方的源表上有一个可编辑的交互式网格,要查看更改,您可以使用交互式网格更改数据)。
我不知道这是否是最好的方法,但它满足我的要求。
更新 05.09.2017:APEX_JSON
添加了Ajax 回调过程和go_pivot
PL/SQL 函数的列表。