【问题标题】:Trying to return dataset from SQL statement with function尝试使用函数从 SQL 语句返回数据集
【发布时间】:2019-01-30 13:23:18
【问题描述】:

我一天中的大部分时间都在研究这个问题,但到目前为止还没有找到正确的答案。我正在尝试找到一种在自定义函数中返回 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,我将不胜感激。谢谢!

【问题讨论】:

    标签: oracle plsql oracle11g


    【解决方案1】:

    为了创建和使用流水线表函数,您必须首先创建一个对象类型。

    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

    【讨论】:

    • 通过只读访问我不能创建数据库对象,所以我不能使用创建或替换函数。我读到我必须将它嵌套在一个匿名块中,这样做对您上面概述的解决方案有何影响?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-14
    • 1970-01-01
    • 2013-07-05
    • 2012-08-02
    • 2012-03-28
    • 2014-09-13
    • 1970-01-01
    相关资源
    最近更新 更多