zoukankan      html  css  js  c++  java
  • pass parameters to view(参数视图)

    参考网址:http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:1448404423206

    参数视图:在实际的业务中,我们可能要进行权限控制,例如:某个部门经理只能看到属于自己管理部门下的员工信息,而不能看到不属于自己管理的部门下的员工的信息,对于系统来说,就要动态的根据当前的登录人所属的部门,进行动态的过滤某些数据,这时候,可以考虑使用参数视图,但是也可以利用一个包的get/set方法进行权限的过滤

    例如,以下是一个简单的实例:

    使用的包:

    CREATE OR REPLACE PACKAGE get_dept_info IS
    
      -- Private variable declarations
      v_dept_no NUMBER;
    
      --setter:procedure
      PROCEDURE set_dept_no_p(i_dept_no NUMBER);
    
      --setter:function
      FUNCTION set_dept_no_f(i_dept_no NUMBER) RETURN VARCHAR2;
    
      --getter
      FUNCTION get_dept_no RETURN NUMBER;
    
    END get_dept_info;
    /
    CREATE OR REPLACE PACKAGE BODY get_dept_info IS
    
      --setter:procedure
      PROCEDURE set_dept_no_p(i_dept_no NUMBER) IS
      BEGIN
        v_dept_no := i_dept_no;
      END;
    
      --setter:function
      FUNCTION set_dept_no_f(i_dept_no NUMBER) RETURN VARCHAR2 IS
      BEGIN
        v_dept_no := i_dept_no;
        RETURN 's';
      END;
    
      --getter
      FUNCTION get_dept_no RETURN NUMBER IS
      BEGIN
        RETURN v_dept_no;
      END;
    
    END get_dept_info;
    /

    视图:

     1 CREATE OR REPLACE VIEW EMP_V AS
     2 SELECT
     3 /********************************************************************************
     4   功能描述:
     5   编 写 人:
     6   修改记录:
     7 ********************************************************************************/
     8        E.EMPNO,
     9        E.ENAME,
    10        E.JOB,
    11        E.MGR,
    12        E.HIREDATE,
    13        E.SAL,
    14        E.COMM,
    15        E.DEPTNO
    16  FROM EMP E
    17  WHERE e.deptno = get_dept_info.get_dept_no()--权限过滤的函数

    测试SQL:

    1 BEGIN
    2   get_dept_info.set_dept_no_p(20);
    3 END;
    4 SELECT * FROM emp_v t

           注意:函数包的getter和setter方法是在一个数据库连接中生效的(即在一个session中),所以,Oracle后台执行的过程中,必须要一个会话中先调用setter方法,在调用getter方法,否则将不会取到任何的值。

    Oracle函数和过程的区别:请参考

    http://www.cnblogs.com/caroline/archive/2011/12/21/2296499.html

    1、

    以下内容是摘录自ASK_TOME中的内容:

    一个网友对使用参数视图的优点进行了概括:

          I have used parameterized views recently and wanted to post my opinion on what I learnt.Following are the advantages of parameterized views. 1. The biggest advantage is that it allows you to join the view with other tables/views thus allowing you to write set based code(可以使用在结果集中使用context中设置的参数). An approach using procedure that returns a ref cursor does notallow this and I found that to be a major limitation. This of course assumes that you want to write the view with upplying the values at run time (i.e. write a parameterized view.) 2. In corner cases, it may help performance as you mentioned above (in rare cases when optimizer is not able to merge.) 可以提高性能

          Cons: 1. It is a painful thing to set the context values each time before testing(在每次测试的时候,都需要进行设置上下文的值). If your views were not parameterized you can run simple selects from the views (e.g. select * from v1) which of course parameterized views dont allowuntill you run the context setting code. (参数视图只有在进行了设置了上下文变量的时候,才会起作用!

          Overall, I felt that in general, one is better off not using them - use straight forward views. In case of performance issues, try the param views out. But dont start out withit in the first place if your needs are fulfilled without them (Which would be the case most of the time.),在需要的时候,使用! Thanx for a brilliant site!
    2、对于复杂的潜逃的SQL语句查询,是否可以使用参数?

    View Code

         This thread has been one of the most useful links in your site... I've a doubt regarding the parameterized views

        1) whether a view which is built on a set of nested queries can be parameterized or not ?  

        2) If yes then upto which level(in nested queries) can i use the parameter set using the "userenv" ? Thanks in advance

    TOM给出的答案:
    1) sure(可以多结果集使用递归参数)
    2) as many as you like(没有嵌套层级的限制)
    also see CREATE CONTEXT, if you have "lots to stuff in there", it'll be very useful. 

    3、How about this alternative(使用临时表进行替代):

         How about creating a parameter table along with the view. or e.g. to create a parameterized view

    1 CREATE VIEW v1 AS SELECT * FROM t1 WHERE c1 = parameter.

        First I will create a Single row table.

    CREATE TABLE param_v1 (param1 VARCHAR2(40));
    Then
    CREATE VIEW v1 AS SELECT t1.* FROM t1, param_v1
    WHERE t1.c1 = param_v1.param1;

    When ever I want to query the view v1 I will first

    1 DELETE FROM param_v1; -- make sure table is empty.
    2 INSERT INTO param_v1 VALUES('MYVALUE'); -- insert parameter.

    Then

    SELECT * FROM v1;

    (remember that param_v1 is a single record table).
    After getting the results of query I can

    DELETE FROM param_v1;

    Tom and all of you, please comment on this.

    以下是tom给出的建议:

         well, if you are going to use a table, don't delete from it, use a global temporary table. (使用临时表进行代替)

         but if you have just but one parameter value row per parameter name - why wouldn't you

    simply use a context?

       (只有一个参数,为什么不使用context ?)

    4、context vs global variable

        consider a context like a global variable:context和全局变量的对比;
        We have a few complex views in our application and we want to "push" a few predicates into these views. What would you suggest be the best option for this ? Session context or global variables ? 使用session中的context变量更好还是全部变量更好?
        Currently our plan is to declare a package with a global variable, set the predicate to this variable and get the variable in the view. Do you think context would be more useful here or makes no difference using either one ?

      TOM的回答:

        global variables will not work with views, so.... application context.
        how would you get the global variable "into the view", views cannot see plsql package variables. 

    问题的补充:

         Thanks for the quick response Tom. Did not express myself clearly there. Ours is a web-app with java as the front-end talking to Oracle. So, right now, the plan is to create a package with "setters" & "getters".(使用getter和setter方法) The "setter" takes an IN parameter & assigns this IN value to the package's global variable. We set the value to this "setter" in java using prepared statement. Next step would be to call the view using prepared statement which calls the "getter" inside it. The "getter" returns this global variable. Hope I am making sense here. Thanks again for your help.

        TOM的回答:

        do not call plsql from sql unless you have to.

        不要在SQL语句中调用PL/SQL除非比必须这么做
        your setter - should call the set context api.

        setter方法应该调用set context的API
        your getter - is just sys_context

        getter方法应该使用sys_context的API
        do not call plsql unless you have to and you very much do not have to here. 

        尽量不要调用PL/SQL除非你必须这么做。

    5、JDBC Connection Pooling and DBMS_SESSION

    Hi Tom,
    
    Talking about the DBMS_SESSION.SET_CONTEXT I have a problem with this when working with JDBC Connection pools. 
    
    1. I have a view that reads from SYS_CONTEXT
    
    create or replace view TableSummaryView as 
    select a.*,  
        row_number() over (partition by 
        a.VProduct_VName,
        a.PriceListType_VName,
        a.PriceGroup_VName,
        a.VSalesOrg_VName,
        a.VChannel_VName,
        a.VPricingCurrency_VISOCode,
        a.PriceRecordPriceListType_VName,
        a.AttributesKey order by a.vvalidity_from, a.created desc) ViewRN 
    from Table a
    where ParentVID in ( select * from THE (select cast(in_list(sys_context('params','epsrlist')) as 
    mytableType) from dual));
    
    2. But before that I set it from Java layer by calling a stored procedure which calls the 
    DBMS_SESSION.SET_CONTEXT.
    
            Connection connection = JDBCHelper.getConnection();
            CallableStatement stmt = null;
            try {
                stmt = connection.prepareCall("{call setepsrlist.epsrlist(?)}");
                stmt.setString(1, epsrList);
                stmt.executeUpdate();
            }
    
    create package setepsrlist is
     procedure epsrlist(epsrstring in varchar2);
    end setepsrlist;
    /
    
    create package body setepsrlist is
     procedure epsrlist(epsrstring in varchar2) is
     begin
      dbms_session.set_context(namespace => 'params', attribute => 'epsrlist', value => epsrstring);
     end epsrlist;
    end setepsrlist;
    /
    
    3. When I execute the query on the View which happens on another Connection and it does not see the value that I have set on the session, since this Connection can potentially be  pointing a new Database Session.(在一个新的链接中,进行数据的查询)

     TOM的回答:
       
    but, I'm confused...

        why would you think a context value set in Oracle session 1 would be or should be visible

    in Oracle session 2? (你为什么认为在session1中的上下文变量可以在或者应该在session2中课件呢????)

    What I meant is a) Get a connection,获取连接 b) Set the context,设置变量 c) Get a connection(this can be a totally different connection),获取另一个链接 d) get the value from the context and it will not be there.将无法获取到变量的值 So how can we be sure that an operation that involves multiple database JDBC connections see the value that is set.
    那我们该如何在JDBC环境下查询他的设置的值呢。

    TOM的回答

    then obviously you cannot rely on that. why would you 
    grab set
    grab YET ANOTHER
    then try to use
    why do java programmers do things like that - to generate a page, you should just
    应该采用如下的方式进行:
    a) grab
    b) generate page
    c) release
    why grab/ungrab over and over and over (this happens all of the time, just to make things *really* hard and confusing)  

    6、Calling Different Views within a View based on Condition ?

      在不同的条件下:查询不同的表

    Hi Tom,
    Is it possible to call two different views from within a single view based on the         condition set by context ?
    E.g I want to create something like :
    Create or replace my_view as
    when TO_DATE(SYS_CONTEXT('userenv','client_info')) = busines_date 
    then 
     select * from current_view
    wehn TO_DATE(SYS_CONTEXT('userenv','client_info')) <> business_date 
    then 
     select * from Historical_view
    Here the current_view and historical_view has same column structure.
    Is there a way wherein we can achieve this ?
    Thanks in advance ,
    Ram.
    针对该问题,网友共提供了三种方法:
    1、
     1 WITH current10 AS
     2  (SELECT LEVEL AS lvl FROM dual CONNECT BY LEVEL < 11),
     3 historical20 AS
     4  (SELECT LEVEL AS lvl FROM dual CONNECT BY LEVEL < 21)
     5 SELECT COUNT(*)
     6   FROM (SELECT *
     7           FROM current10
     8          WHERE rownum = CASE
     9                  WHEN sys_context('userenv', 'client_info') = '10' OR
    10                       sys_context('userenv', 'client_info') IS NULL THEN
    11                   rownum
    12                  ELSE
    13                   0
    14                END
    15         UNION ALL
    16         SELECT *
    17           FROM historical20
    18          WHERE rownum = CASE
    19                  WHEN sys_context('userenv', 'client_info') = '20' OR
    20                       sys_context('userenv', 'client_info') IS NULL THEN
    21                   rownum
    22                  ELSE
    23                   0
    24                END)

    2、TOM提供的方法:

    1 select * from t1 where (nvl(sys_context(...),'10') = '10') 
    2 union all 
    3 select * from t2 where (nvl(sys_context(...),'20') = '20') 

        you'll find that a tad more efficient as well as the where clause could be used to actually prevent us from having to scan t1 or t2 - whereas that case could not

    3、网友提供的另一种解决方法:

     1 WITH current10 AS
     2  (SELECT LEVEL AS lvl FROM dual CONNECT BY LEVEL < 11),
     3 historical20 AS
     4  (SELECT LEVEL AS lvl FROM dual CONNECT BY LEVEL < 21)
     5 SELECT COUNT(*)
     6   FROM (SELECT *
     7           FROM current10
     8          WHERE coalesce(sys_context('userenv', 'client_info'), '10') = '10'
     9         UNION ALL
    10         SELECT *
    11           FROM historical20
    12          WHERE coalesce(sys_context('userenv', 'client_info'), '20') = '20')

    Tom使用了10046事件:

    1 alter session set events '10046 trace name context forever, level 12';

    7、使用/*+ gather_plan_statistics */HINT执行计划信息的收集

    select /*+ gather_plan_statistics */ * from v;

    查询执行计划结果:

    1 select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));

    8、parameterized view examples in your site

    Hi Tom,
       I am looking for a view where the select query has multiple conditions.So,  the paramterized view will need to be set multiple values for multiple parameters.As per this page,it should be possible through dbms_session.set_context and reference later using sys_context . Can you please provide me an example ?
    
     TOM提供的答案:
       
     just reference sys_context as many times as you would like.
    create context foo and then set in foo the values v1, v2, v3 (or whatever) and reference
    where x = sys_context( 'foo', 'v1' ) and
    y = sys_context( 'foo', 'v2' ) ... 

     9、Parameterized view  and in predicte

    Hi Tom,
        you have mentioned the method with setting the parameter 'client_info' to parameterize a view. Your example was:
    create view myview
    as select * from t where x = userenv('client_info')
    /
    and then:
    SQL> exec dbms_application_info.set_client_info('my_data')
    SQL> select * from myview;
    
          That works very good, but what should I do, if I want to select something like  that:
    create view myview
    as select * from t where x in userenv('client_info')
        I tried setting the parameter with something like that:
    exec dbms_application_info.set_client_info('(''abc'',''xyz'')');
    But that doesn't work.What the best way to parameterized a range?
    
    TOM给出的答案:
    http://tkyte.blogspot.com/2006/06/varying-in-lists.html
    该网址可能直接无法直接访问,需要使用代理访问
    推荐一个代理网站:
    http://proxyie.cn/

     

     

     

  • 相关阅读:
    保存时出错jup
    Spyder默认页面布局调整
    根据所处位置提取单元格内容的函数(left、right、mid)和查找字符串位于单元格内容第几位的函数(find)
    excel打印出现多余空白页
    Excel的布尔值运算
    excel VBA一个fuction同时执行多个正则表达式,实现方法
    excel VBA把一个单元格内容按逗号拆分并依次替换到另一个单元格的括号里面(本题例子,把文本中的括号换成{答案}的格式,并按顺序填空)
    excel自动记录项目完成进度,是否逾期,逾期/提前完成天数,计算天数可以把now()改为today()
    jquery循环动画
    jquery动画(控制动画隐藏、显示时间轴)
  • 原文地址:https://www.cnblogs.com/caroline/p/2698334.html
Copyright © 2011-2022 走看看