【问题标题】:creating parameterized views in oracle11g在 oracle11g 中创建参数化视图
【发布时间】:2012-02-19 22:25:57
【问题描述】:

我有一个带有嵌套和左连接的大查询,我需要从中创建一个视图,以免从应用程序中运行它。问题是我需要日期范围和其他一些字段作为输入参数,因为每个请求的前端都会有所不同。 我刚刚查看并看到一些帖子提到使用 SYS_CONTEXT 进行参数化视图,并且需要确切知道如何使用 2 个参数创建视图 - fromdate, todate 以及如何从应用程序调用视图。

仅供参考,我正在使用 grails/groovy 开发应用程序。 这是我想从中创建视图的查询..

 select 
    d.dateInRange as dateval,
    eventdesc,
    nvl(td.dist_ucnt, 0) as dist_ucnt
from (
    select 
        to_date(fromdate,'dd-mon-yyyy') + rownum - 1 as dateInRange
    from all_objects
    where rownum <= to_date(fromdate,'dd-mon-yyyy') - to_date(todate,'dd-mon-yyyy') + 1
) d
left join (
    select 
        to_char(user_transaction.transdate,'dd-mon-yyyy') as currentdate,
        count(distinct(grauser_id)) as dist_ucnt,
        eventdesc 
    from
        gratransaction, user_transaction 
  where gratransaction.id = user_transaction.trans_id and 
  user_transaction.transdate between to_date(fromdate,'dd-mon-yyyy') and to_date(todate,'dd-mon-yyyy') 
    group by  to_char(user_transaction.transdate, 'dd-mon-yyyy'), eventdesc 
) td on td.currentdate = d.dateInRange order by d.dateInRange asc

【问题讨论】:

    标签: oracle views oracle11g


    【解决方案1】:

    上下文方法描述在这里:http://docs.oracle.com/cd/B28359_01/network.111/b28531/app_context.htm

    例如(示例改编自上述链接)

    CREATE CONTEXT dates_ctx USING set_dates_ctx_pkg;
    
    CREATE OR REPLACE PACKAGE set_dates_ctx_pkg IS 
      PROCEDURE set(d1 in date, d2 in date); 
    END; 
    /
    
    CREATE OR REPLACE PACKAGE BODY set_dates_ctx_pkg IS
      PROCEDURE set(d1 in date, d2 in date) IS 
      BEGIN 
        DBMS_SESSION.SET_CONTEXT('dates_ctx', 'd1', TO_CHAR(d1,'DD-MON-YYYY'));
        DBMS_SESSION.SET_CONTEXT('dates_ctx', 'd2', TO_CHAR(d2,'DD-MON-YYYY'));
      END;
    END;
    /
    

    然后,在您的应用程序中设置日期:

    BEGIN set_dates_ctx_pkg.set(mydate1, mydate2); END;
    /
    

    然后,查询参数:

    SELECT bla FROM mytable
    WHERE mydate
      BETWEEN TO_DATE(
                SYS_CONTEXT('dates_ctx', 'd1')
              ,'DD-MON-YYYY')
          AND TO_DATE(
                SYS_CONTEXT('dates_ctx', 'd2')
              ,'DD-MON-YYYY');
    

    这种方法的优点是查询非常友好;它在运行时不涉及 DDL 或 DML,因此无需担心事务;而且速度非常快,因为它不涉及 SQL - PL/SQL 上下文切换。

    或者:

    如果你无法使用上下文方法和 John 的包变量方法,另一种是将参数插入到表中(例如,全局临时表,如果你在同一个会话中运行查询),然后加入从视图到该表。缺点是您现在必须确保在运行查询时运行一些 DML 来插入参数。

    【讨论】:

    • 我们不能使用函数过程,但我会研究选项并尝试这里建议的解决方案
    • 为什么你不能使用过程、函数或包?如果您使用的是 Oracle,则没有充分的理由避免使用它们。
    【解决方案2】:

    我刚刚为这个烦人的 Oracle 缺点做了一个解决方法。像这样

    create or replace package pkg_utl
    as
      type test_record is record (field1 number, field2 number, ret_prm_date date);
      type test_table is table of test_record;
      function get_test_table(prm_date date) return test_table pipelined;
    end;
    /
    
    create or replace package body pkg_utl
    as
      function get_test_table(prm_date date) return test_table pipelined
      is
      begin
        for item in (
          select 1, 2, prm_date
          from dual
        ) loop
          pipe row (item);
        end loop;
        return;
      end get_test_table;
    end;
    /
    

    它仍然需要一个包,但至少我可以更方便地使用它:

    select *
    from table(pkg_utl.get_test_table(sysdate))
    

    我不确定性能...

    【讨论】:

    • 这究竟如何满足将参数推送到视图中的要求?您的示例查询仍然在视图中硬编码参数 (sysdate)。你也可以直接在视图中使用sysdate,不需要包。
    • 嗨,杰弗里。 sysdate 只是一个例子——你可以放任何值。这里的关键是您可以像视图一样重用查询(在我的示例中是“select 1, 2, prm_date from dual”),但带有外部参数(prm_date)。
    • 所以你建议用流水线函数内的查询完全替换视图?
    • 是的,完全正确。只是作为一种选择。
    • 这更类似于 MS “表值函数”,对我来说,这很简单。
    【解决方案3】:

    在视图中使用参数的一种方法是创建一个包,该包将设置参数的值并具有可调用的函数来获取这些值。例如:

    create or replace package MYVIEW_PKG as
      procedure SET_VALUES(FROMDATE date, TODATE date);
    
      function GET_FROMDATE
        return date;
    
      function GET_TODATE
        return date;
    end MYVIEW_PKG;
    
    create or replace package body MYVIEW_PKG as
      G_FROM_DATE   date;
      G_TO_DATE     date;
    
      procedure SET_VALUES(P_FROMDATE date, P_TODATE date) as
      begin
        G_FROM_DATE := P_FROMDATE;
        G_TO_DATE := P_TODATE;
      end;
    
      function GET_FROMDATE
        return date is
      begin
        return G_FROM_DATE;
      end;
    
      function GET_TODATE
        return date is
      begin
        return G_TO_DATE;
      end;
    end MYVIEW_PKG;
    

    然后您的视图可以这样创建:

    create or replace view myview as
        select 
            d.dateInRange as dateval,
            eventdesc,
            nvl(td.dist_ucnt, 0) as dist_ucnt
        from (
            select 
                MYVIEW_PKG.GET_FROMDATE + rownum - 1 as dateInRange
            from all_objects
            where rownum <= MYVIEW_PKG.GET_FROMDATE - MYVIEW_PKG.GET_TODATE + 1
        ) d
        left join (
            select 
                to_char(user_transaction.transdate,'dd-mon-yyyy') as currentdate,
                count(distinct(grauser_id)) as dist_ucnt,
                eventdesc 
            from
                gratransaction, user_transaction 
          where gratransaction.id = user_transaction.trans_id and 
          user_transaction.transdate between MYVIEW_PKG.GET_FROMDATE and MYVIEW_PKG.GET_TODATE
            group by  to_char(user_transaction.transdate, 'dd-mon-yyyy'), eventdesc 
        ) td on td.currentdate = d.dateInRange order by d.dateInRange asc;
    

    要运行它,您必须先设置值:

    exec MYVIEW_PKG.SET_VALUES(trunc(sysdate)-1,trunc(sysdate));
    

    然后对它的调用将使用这些值:

    select * from myview;
    

    【讨论】:

    • hmm... 看起来这种方法肯定需要函数/包...在这个实现中我们是不允许的。我确实在网上看到了一些解决方案,但其中大多数都有功能/程序
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-06
    • 2014-04-25
    相关资源
    最近更新 更多