Каковы наилучшие способы реализации динамического матричного отчета с помощью APEX?
мне нужно выполнить эту задачу с помощью Oracle Application Express framework.
допустим, у нас есть такой запрос:
select
col1,
col2,
val1,
val2,
val3,
val4,
val5,
val6,
val7,
val8,
val9,
val10,
val11
from table(mega_function(city => ?, format => ?, percent => ?, days => ?));
и этот запрос возвращает что-то вроде этого (см. в формате 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
проще говоря, запрос базируется на конвейерной функции, которая принимает некоторые параметры и возвращает некоторый набор значений для разных пар значений первых двух столбцов col1;col2
.
что мне нужно реализовать, это матричный отчет где значения col1
используются в качестве строк отчета и значений col2
как колонны. На перекрестке есть клетки, которые содержат набор значений для пары с форматирование и стили. Что также необходимо-это сортировка по строкам (которая должна сортировать столбцы по значениям столбца "val1").
или если мы покажем эти потребности на макете:
Итак, вопрос в том, каковы наилучшие практики для реализации такого матричный отчет с некоторыми взаимодействиями и пользовательскими стилями?
то, что я уже пытался смотреть на:
- интерактивная функциональность сводного отчета (https://docs.oracle.com/cd/E71588_01/AEEUG/managing-pivot-reports.htm#AEEUG29137) - не хватает настройки, плохо работает со многими значениями, особенно когда они не являются числами.
- классический отчет на основе функции-я реализовал функция PL/SQL что возвращает динамический сводный SQL-запрос в свойствах отчета
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, чтобы заголовки были на своих местах), и я не знаю, как сделать строки сортируемыми здесь. - PL/SQL Dynamic Content Region - я не пытался что-то здесь закодировать, но я понимаю, что здесь можно сделать все, что угодно, используя пакет HTP и APEX API. Хитрость в том, что это решение довольно сложное, мне нужно будет реализовать всю логику отчета "с нуля", и я считаю, что есть лучший и более простой способ добиться успеха в этой задаче, которого я не знаю.
3 ответов
к сожалению, ни один из вариантов, упомянутых в вопросе, не отвечал всем требованиям из-за условий, в которых будет жить отчет:
- данные должны динамически обновляться каждые, скажем, 5 секунд.
- состояние отчета должно быть сохранено поверх обновлений данных.
- количество столбцов отчета является переменным (определение столбцов представлены данные), число строк переменной. Доклад должен иметь рассортировать, параметры разбиения на страницы и прокрутки (по X и Y). Все вещи (сортировка и т. д.) должно быть сделано на стороне клиента.
- стили и пользовательский рендеринг ячеек должны применяться к ячейкам таблицы.
- ячейки должны быть кликабельными (щелчок должен генерировать событие, которое interceptable).
я понял, что для такой задачи лучше манипулировать DOM на лету на стороне клиента, а не использовать некоторые нестандартные решения APEX, такие как классические отчеты, интерактивные отчеты или сетки.
я объекты DataTable.js плагин jQuery для этого подхода. После недели оценки технологии и изучения некоторого базового JavaScript (который не является моим основным навыком), у меня было следующее:
в приложении APEX я реализовал процесс обратного вызова Ajax (называемый TEST_AJAX
), он запускает код PL / SQL, который возвращает JSON-object в 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;
на 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;
затем я создал статическую область контента на странице, источник которой следующий:
<div id="datatable_test_container"></div>
я загрузил CSS и JS файлы DataTables.js к статическим файлам приложения и включил их в свойства страницы. В на странице Function and Global Variable Declaration
я добавил этот код JavaScript:
var $ = apex.jQuery;
var table;
var columns;
var rows;
//table initialization function
function table_init(json_data) {
return $('#datatable_test').DataTable({
//column defaults options
columnDefs: [{
"data": null,
"defaultContent": "-",
"targets": "_all"
}],
columns: json_data.columns,
data: json_data.data,
stateSave: true
});
}
//function to asynchronously get data from APEX AJAX CALLBACK
//process and then to draw a table based on this data
function worker() {
//run the process called TEST_JSON
apex.server.process(
"TEST_JSON", {}, {
success: function(pData) {
//on first run we need to initialize the table
if (typeof table == 'undefined') {
//save current data for future use
columns = $.extend(true, [], pData.columns);
rows = $.extend(true, [], pData.data);
//generate empty html-table in the container
$('#datatable_test_container').append('<table id = "datatable_test" class = "display" cellspacing = "0" width = "100%" > < /table>');
//init the table
table = table_init(pData);
//when columns of the table changes we need to
//reinitialize the table (DataTables require it due to architecture)
} else if (JSON.stringify(columns) !=
JSON.stringify(pData.columns)) {
//save current data for future use
columns = $.extend(true, [], pData.columns);
rows = $.extend(true, [], pData.data);
//delete the table from DOM
table.destroy(true);
//generate empty html-table in the container
$('#datatable_test_container').append('<table id = "datatable_test" class = "display" cellspacing = "0" width = "100%" > < /table>');
//reinit the table
table = table_init(pData);
}
//if data changes, clear and re-draw the table
else if (JSON.stringify(rows) != JSON.stringify(pData.data)) {
//save current data for future use
//we don't need to save the columns, they didn't change
rows = $.extend(true, [], pData.data);
//clear table, add rows from recieved JSON-object, re-
draw the table with new data
table.clear().rows.add(pData.data).draw(false);
}
//if nothing changes, we do nothing
}
}
);
//repeat the procedure in a second
setTimeout(worker, 1000);
};
на Execute when Page Loads
I добавлено:
$(document).ready(function() {
worker();
});
что все это делает:
- статический
<div>
в области статического содержимого получает пустой таблица, в которой применяется конструктор DataTables. - JavaScript-код начинает свою работу с запуска сервера обратного вызова Ajax process, а при успешном использовании результата этот процесс возвращается.
- конструктор DataTables поддерживает различные типы источников данных, например он может анализировать html-таблицу или сделайте ajax-вызов, но я предпочтительно использовать процесс APEX, а затем основывать таблицу на JSON-объект, который возвращает этот процесс.
- затем скрипт наблюдает за изменениями. При изменении столбцов таблица удаляется из документа и повторно инициализируется с использованием новых данных, если изменяется только строка, тогда таблица просто перерисовывается с этими данными. Если ничего не изменится в данных тогда сценарий ничего не делает.
- этот процесс повторяется каждую секунду.
как a в результате получается полностью интерактивный, динамически обновляемый отчет с такими параметрами, как сортировка, подкачка, поиск, обработка событий и так далее. И все это делается на стороне клиента без дополнительных запросов к серверу.
вы можете проверить результат с помощью этого live demo (верхняя область-отчет DataTables, под ним есть редактируемая интерактивная сетка в исходной таблице, чтобы увидеть изменения, вы можете изменить данные с помощью интерактивного сетка.)
я не знаю, является ли это лучшим подходом, но он отвечает моим требованиям.
обновлено 05.09.2017: добавлен список APEX_JSON
процесс обратного вызова Ajax и go_pivot
функция PL/SQL.
вы правы. Я только предоставил мнение, основанное на моем раннем понимании вашего описания требований.. Теперь, когда я прочитал это более внимательно, я передумал, потому что понял, что это не сложная матрица.. На самом деле у меня их много..
Я не знаю лучших практик как таковых, но я могу поделиться с вами тем, что я сделал с аналогичными требованиями:
для матричных отчетов я предпочитаю классические отчеты, я ставлю свои критерии фильтрации на раздел заголовка (как и в вашем макете) и на основе выбора пользователя информация меняется очень красиво. Вот как я управляюсь с фильтрацией и сортировкой.
самая сложная часть (IMO) с вашими требованиями-это проверка ячеек для целей экспорта.. Вы должны иметь возможность динамически включать элемент управления toggle в своем запросе, и с помощью AJAX вы должны иметь возможность выбирать выбранные для экспорта.
на основе ваших требований APEX, вероятно, не является правильным инструментом, вы будете бесконечно ограничены базовыми библиотеками и возможностями JQuery и т. д.
Я бы не рискнул разрабатывать такое приложение на APEX, на мой взгляд, требования слишком далеки от технологии, предлагаемой в APEX.
с другой стороны вы говорите о производительности БД.. Хорошо, что вы принимаете это во внимание на этапе планирования, но плохо, потому что вы ограничиваете уже себя.. есть варианты... например, получить опцию в памяти в базе данных и / кэшировать результаты из материализованного представления.. Закрепите таблицы в памяти.