Попытка вернуть набор данных из оператора SQL с помощью функции - PullRequest
0 голосов
/ 30 января 2019

Я копался в этом большую часть дня, но до сих пор не смог найти правильный ответ.Я пытаюсь найти способ вернуть результаты запроса SQL в пользовательской функции.Все данные в нашей системе датируются как транзакциями, так и датами вступления в силу, и мы обычно должны сравнивать данные между двумя точками времени.Прямо сейчас я использую предложение WITH, чтобы получить два разных набора данных («До» и «После»).Проблема в том, что запросы, используемые для создания этих наборов данных, очень длинные, и каждый CTE - это одно и то же, только с разными датами вступления в силу.Я хотел бы найти способ создать функцию, в которую я могу передать даты вступления в силу / транзакции для сравнения, чтобы у меня не было такой избыточной логики в моем SQL.Вот подвох - у меня есть доступ только для чтения и я не могу создавать объекты в БД.Я читал, что могу обойтись оператором Declare, но пока не смог сделать это правильно.

Вот пример того, что у меня сейчас.Я значительно упростил запрос, так что это не полный беспорядок.

WITH    effective_date AS ( 
        SELECT  to_date(:EFFDT)                 AS  effdt, 
                to_date(:REPORT_DATE_BEFORE)    AS  report_dt_before, 
                to_date(:REPORT_DATE_AFTER)     AS  report_dt_after

        FROM    dual), 

        election_data_before AS (
        SELECT  *

        FROM                effective_date                  efd

                CROSS JOIN  elections                       e

        WHERE   efd.effdt               >=  e.start_dt
        AND     efd.effdt               <   e.until_dt
        AND     efd.report_dt_before    >=  e.tran_start_dt
        AND     efd.report_dt_before    <   e.tran_until_dt), 

        election_data_after AS (
        SELECT  *

        FROM                effective_date                  efd

                CROSS JOIN  elections                       e

        WHERE   efd.effdt               >=  e.start_dt
        AND     efd.effdt               <   e.until_dt
        AND     efd.report_dt_after     >=  e.tran_start_dt
        AND     efd.report_dt_after     <   e.tran_until_dt)

SELECT  ...

FROM                    election_data_before            edb

        INNER JOIN      election_data_after             eda
                    ON      edb.employee_id         =   eda.employee_id
                    AND     edb.benefit_type        =   eda.benefit_type

WHERE   ...

Это выглядит не так уж плохо, но, как я уже сказал, это чрезвычайно упрощено.Вот что я хотел бы сделать.Я знаю, что это мусорный код, просто пытаюсь проиллюстрировать то, что я рисую.

FUNCTION    elections   (   effdt   date,   report_dt date )
RETURN  (
        SELECT  *

        FROM    elections  e

        WHERE   effdt               >=  e.start_dt
        AND     effdt               <   e.until_dt
        AND     report_dt           >=  e.tran_start_dt
        AND     report_dt           <   e.tran_until_dt)

SELECT  ...

FROM                    elections(:EFFDT, :REPORT_DT_BEFORE)   edb
                    ON      pp.employee_id          =   edb.employee_id

        INNER JOIN      elections(:EFFDT, :REPORT_DT_AFTER)    eda
                    ON      pp.employee_id          =   eda.employee_id
                    AND     edb.benefit_type        =   eda.benefit_type

WHERE   ...

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

1 Ответ

0 голосов
/ 30 января 2019

Чтобы создать и использовать конвейерную табличную функцию, вы должны сначала создать тип объекта.

create or replace type election_type as object 
(
  col1 varchar2(100),
  col2 date,
  col3 number       -- Here you define the name and datatype of the columns you want
                    -- to return from the select query.
);
/

create or replace type election_type_tab as table of election_type;
  -- You need a collection (nested table) type to return multiple records 
   -- of the type defined above from your function

Теперь определите вашу функцию, используя неявный курсор для цикла для извлечения и передачи строк вызывающей стороне..

CREATE OR REPLACE FUNCTION fn_elections (
     effdt DATE,
     report_dt DATE
) RETURN election_type_tab
     PIPELINED
     AS
BEGIN

     FOR rec IN (
         SELECT * --This should return the same columns as that of election_type
          FROM elections e --,some_othertable s
          WHERE effdt     >= e.start_dt AND 
                    effdt < e.until_dt 
          AND   report_dt >= e.tran_start_dt 
            AND report_dt < e.tran_until_dt
     ) LOOP
          PIPE ROW ( election_type(rec.col1,rec.col2,rec.col3) );
     END LOOP;
     return;
END;
/

Затем вы можете назвать это так.

 select * from TABLE(fn_elections(sysdate,sysdate+1)); --or some other date argument

Демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...