Каков наилучший подход к созданию отчета Oracle Apex Interactive с определенными пользователем параметрами? - PullRequest
0 голосов
/ 05 июля 2018

Я пытаюсь создать отчет в Oracle Apex с параметрами пользователя. Во-первых, у меня есть одна форма, где пользователь выбирает частоту, дату, для которого должен быть отчет, и другие параметры. Я отправляю все эти детали на следующую страницу, где будет представлен этот Интерактивный отчет. До сих пор я пытался построить запрос в теле функции PL / SQL, возвращающем SQL-запрос, но каждый раз, когда я получал сообщение об ошибке ниже.

ORA-20999: WWV_FLOW_EXEC.NULL_QUERY_RETURNED_BY_FUNCTION

Пример моего кода:

declare
    single_date         char(12)  := ''''||TO_CHAR(TRUNC(to_date(:P21_DATE, 'DD-MM-YYYY')), 'DD.MM.YYYY')||'''';
    start_date_value    char(12)  := ''''||TO_CHAR(TRUNC(to_date(:P21_DATE, 'DD-MM-YYYY'), 'IW'), 'DD.MM.YYYY')||'''';
    end_date_value      char(12)  := ''''||TO_CHAR(TRUNC(to_date(:P21_DATE, 'DD-MM-YYYY'), 'IW') + 6, 'DD.MM.YYYY')||'''';
    first_month_value   char(12)  := ''''||to_char(trunc(to_date(:P21_DATE, 'DD-MM-YYYY'), 'MM'), 'DD.MM.YYYY')||'''';
    last_month_value    char(12)  := ''''||to_char(LAST_DAY(to_date(:P21_DATE,'DD-MM-YYYY')), 'DD.MM.YYYY')||'''';
    first_year_value    char(12)  := ''''||to_char(trunc(to_date(:P21_DATE, 'DD-MM-YYYY'), 'YYYY'), 'DD.MM.YYYY')||'''';
    last_year_value     char(12)  := ''''||to_char(last_day(add_months(to_date(:P21_DATE,'DD-MM-YYYY'),12 - to_number(to_char(to_date(:P21_DATE,'DD-MM-YYYY'),'mm')))), 'DD.MM.YYYY')||'''';
begin
    if :P21_DETAILS = 1 then
        if :P21_FREQUENCY = 1 then
            if :P21_FOR = 1 then
                return q'~
                SELECT <columns> FROM <table> WHERE <date> = '||single_date||' AND <something> = '||lower(:APP_USER)||';
                ~';
            elsif :P21_FOR = 2 then
                return q'~
                SELECT <columns> FROM <table> WHERE <date> = '||single_date||' AND <something> = '||lower(:P21_PERSON)||';
                ~';
            elsif :P21_FOR = 3 then
                return q'~
                SELECT <columns> FROM <table> WHERE <date> = '||single_date||';
                ~';
            end if;
        elsif :P21_FREQUENCY = 2 then
            if :P21_FOR = 1 then
                return q'~
                SELECT <columns> FROM <table> WHERE <date> BETWEEN TO_DATE('||start_date_value||', ''DD.MM.YYYY'') AND TO_DATE('||end_date_value||', ''DD.MM.YYYY'') AND <something> = '||lower(:APP_USER)||';
                ~';
            elsif :P21_FOR = 2 then
                return q'~
                SELECT <columns> FROM <table> WHERE <date> BETWEEN TO_DATE('||start_date_value||', ''DD.MM.YYYY'') AND TO_DATE('||end_date_value||', ''DD.MM.YYYY'') AND <something> = '||lower(:P21_PERSON)||';
                ~';
            elsif :P21_FOR = 3 then
                return q'~
                SELECT <columns> FROM <table> WHERE <date> BETWEEN TO_DATE('||start_date_value||', ''DD.MM.YYYY'') AND TO_DATE('||end_date_value||', ''DD.MM.YYYY'');
                ~';
            end if;
        elsif :P21_FREQUENCY = 3 then
            if :P21_FOR = 1 then
                return q'~
                SELECT <columns> FROM <table> WHERE <date> BETWEEN TO_DATE('||first_month_value||', ''DD.MM.YYYY'') AND TO_DATE('||last_month_value||', ''DD.MM.YYYY'') AND <something> = '||lower(:APP_USER)||';
                ~';
            elsif :P21_FOR = 2 then
                return q'~
                SELECT <columns> FROM <table> WHERE <date> BETWEEN TO_DATE('||first_month_value||', ''DD.MM.YYYY'') AND TO_DATE('||last_month_value||', ''DD.MM.YYYY'') AND <something> = '||lower(:P21_PERSON)||';
                ~';
            elsif :P21_FOR = 3 then
                return q'~
                SELECT <columns> FROM <table> WHERE <date> BETWEEN TO_DATE('||first_month_value||', ''DD.MM.YYYY'') AND TO_DATE('||last_month_value||', ''DD.MM.YYYY'');
                ~';
            end if;
        elsif :P21_FREQUENCY = 4 then
            if :P21_FOR = 1 then
                return q'~
                SELECT <columns> FROM <table> WHERE <date> BETWEEN TO_DATE('||first_year_value||', ''DD.MM.YYYY'') AND TO_DATE('||last_year_value||', ''DD.MM.YYYY'') AND <something> = '||lower(:APP_USER)||';
                ~';
            elsif :P21_FOR = 2 then
                return q'~
                SELECT <columns> FROM <table> WHERE <date> BETWEEN TO_DATE('||first_year_value||', ''DD.MM.YYYY'') AND TO_DATE('||last_year_value||', ''DD.MM.YYYY'') AND <something> = '||lower(:P21_PERSON)||';
                ~';
            elsif :P21_FOR = 3 then
                return q'~
                SELECT <columns> FROM <table> WHERE <date> BETWEEN TO_DATE('||first_year_value||', ''DD.MM.YYYY'') AND TO_DATE('||last_year_value||', ''DD.MM.YYYY'');
                ~';
            end if;
        end if;
    end if;
end;

Пробовал и другие способы, код ниже, но безуспешно.

ORA-01403: данные не найдены

declare
    date_modify         char(12)  := :P24_DATE;
    single_date         char(12)  := ''''||TO_CHAR(TRUNC(to_date(date_modify, 'DD.MM.YYYY')), 'DD.MM.YYYY')||'''';
    start_date_value    char(12)  := ''''||TO_CHAR(TRUNC(to_date(date_modify, 'DD.MM.YYYY'), 'IW'), 'DD.MM.YYYY')||'''';
    end_date_value      char(12)  := ''''||TO_CHAR(TRUNC(to_date(date_modify, 'DD.MM.YYYY'), 'IW') + 6, 'DD.MM.YYYY')||'''';
    first_month_value   char(12)  := ''''||to_char(trunc(to_date(date_modify, 'DD.MM.YYYY'), 'MM'), 'DD.MM.YYYY')||'''';
    last_month_value    char(12)  := ''''||to_char(LAST_DAY(to_date(date_modify,'DD.MM.YYYY')), 'DD.MM.YYYY')||'''';
    first_year_value    char(12)  := ''''||to_char(trunc(to_date(date_modify, 'DD.MM.YYYY'), 'YYYY'), 'DD.MM.YYYY')||'''';
    last_year_value     char(12)  := ''''||to_char(last_day(add_months(to_date(date_modify,'DD.MM.YYYY'),12 - to_number(to_char(to_date(date_modify,'DD.MM.YYYY'),'mm')))), 'DD.MM.YYYY')||'''';
    query               varchar2(500);
begin
    if apex_application.g_f01(1) = 1 then
        if :P24_TYPE = 1 then
            query := 'SELECT <some columns> FROM <table> WHERE <date> = '||single_date||'';
        elsif :P24_TYPE = 2 then
            query := 'SELECT <some columns> FROM <table> WHERE <date> BETWEEN TO_DATE('||start_date_value||', ''DD.MM.YYYY'') AND TO_DATE('||end_date_value||', ''DD.MM.YYYY'')';
        elsif :P24_TYPE = 3 then
            query := 'SELECT <some columns> FROM <table> WHERE <date> BETWEEN TO_DATE('||first_month_value||', ''DD.MM.YYYY'') AND TO_DATE('||last_month_value||', ''DD.MM.YYYY'')';
        elsif :P24_TYPE = 4 then
            query := 'SELECT <some columns> FROM <table> WHERE <date> BETWEEN TO_DATE('||first_year_value||', ''DD.MM.YYYY'') AND TO_DATE('||last_year_value||', ''DD.MM.YYYY'')';
        end if;
    end if;
    if :P24_PERSON <> 'no' then
        query := query||' AND <something_else> = '''||lower(:P24_PERSON)||'''';
    end if;

    return query;
end;

Заранее спасибо.

1 Ответ

0 голосов
/ 06 июля 2018

Если посмотреть на прошлые и логические проблемы, ваш код в настоящее время является SQL-инъекцией кошмаром, оставляя вашу страницу уязвимой для пользователей, запрашивающих информацию, которой они не могут. Это также заставляет использовать литералы, которые слишком быстро уносят ваш общий SQL, принудительно анализируя.

Существует встроенная функция, которая позволяет вам ссылаться на страницу с IR и предварительно заполнять фильтры, как если бы вы использовали их вручную.

https://docs.oracle.com/database/apex-5.1/HTMDB/linking-to-interactive-reports.htm#HTMDB30108

...