尝试使用功能从SQL语句返回数据集

时间:2019-01-29 21:11:59

标签: oracle plsql oracle11g

我整天大部分时间都在研究这个问题,但到目前为止仍找不到正确的答案。我试图找到一种在自定义函数中返回SQL查询结果的方法。我们系统中的所有数据都是交易日期和生效日期,通常需要我们在两个时间点之间比较数据。现在,我使用WITH子句提取两个不同的数据集(“ Before”和“ After”)。问题在于用于创建这些数据集的查询非常长,每个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 :(得分:0)

要创建和使用管道表功能,必须首先创建一个对象类型。

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

现在,使用隐式光标for循环定义函数,以提取行并将行传递给调用方。

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

Demo