【问题标题】:PL/SQL: How do I declare session variables?PL/SQL:如何声明会话变量?
【发布时间】:2010-09-23 00:23:10
【问题描述】:

如何在 PL/SQL 中声明会话变量 - 一个只会在会话期间持续存在的变量,而无需我将其存储在数据库本身中?

【问题讨论】:

    标签: oracle plsql


    【解决方案1】:

    您可以使用“用户创建的上下文”来存储会话内跨多个单元共享的数据。

    首先,创建一个上下文:

    CREATE CONTEXT SYS_CONTEXT ('userenv', 'current_schema')|| '_ctx' USING PKG_COMMON
    

    其次,创建一个可以管理你的上下文的包:

    CREATE OR REPLACE PACKAGE PKG_COMMON
    IS
       common_ctx_name   CONSTANT VARCHAR2 (60)
                     := SYS_CONTEXT ('userenv', 'current_schema')
                        || '_ctx';
    
       FUNCTION fcn_get_context_name RETURN VARCHAR2;
       PROCEDURE prc_set_context_value (var_name VARCHAR2, var_value NUMBER);
    END;
    
    CREATE OR REPLACE PACKAGE BODY PKG_COMMON
    IS
       FUNCTION fcn_get_context_name
          RETURN VARCHAR2
       IS
       BEGIN
          RETURN common_ctx_name;
       END;
    
       PROCEDURE prc_set_context_value (var_name VARCHAR2, var_value NUMBER)
       IS
       BEGIN
          DBMS_SESSION.set_context (common_ctx_name, var_name, var_value);
       END;
    END;
    

    prc_set_context_value 可以更高级,这只是一个例子。 有了上下文和创建的包,您就可以开始使用它们了。 使用过程调用设置上下文变量

    begin
      PKG_COMMON.prc_set_context_value('MyVariable', 9000)
    end;
    

    并在任何地方使用它 - 任何过程、包、函数或事件视图。

    CREATE VIEW V_TEST AS
      SELECT ID, LOGIN, NAME 
        FROM USERS 
       WHERE ROLE_ID =  SYS_CONTEXT(PKG_COMMON.FCN_GET_CONTEXT_NAME, 'MyVariable')
    

    欲了解更多信息,请参阅http://www.psoug.org/reference/sys_context.html

    【讨论】:

    • 当我创建上下文时,它说:ORA-28265:不允许以“sys_”开头的命名空间。我试图将其设置为变量。但它设置变量名而不是值
    • 为什么要使用CURRENT_SCHEMA动态构建上下文名称?它需要是全球唯一的吗?
    【解决方案2】:

    您创建一个包级变量。这是一个最小的例子:

    CREATE OR REPLACE PACKAGE my_package
    AS
        FUNCTION get_a RETURN NUMBER;
    END my_package;
    /
    
    CREATE OR REPLACE PACKAGE BODY my_package
    AS
        a  NUMBER(20);
    
        FUNCTION get_a
        RETURN NUMBER
        IS
        BEGIN
          RETURN a;
        END get_a;
    END my_package;
    /
    

    如果您这样做,您应该阅读(并正确处理)ORA-04068 错误。每个数据库会话都有它自己的 a 值。你可以试试这个:

    SELECT my_package.get_a FROM DUAL;
    

    【讨论】:

    • 我假设您需要一个过程来设置值?
    • @jpmc26 有一个二传手是正常的。我认为您可以将变量放在包中(而不是包体)以使其公开。
    【解决方案3】:

    我喜欢使用 简短但直观的语法,因此会创建例如一些 ctx,只提供一个函数来设置和获取一些全局“变量”
    (仅对当前会话有效;在我的情况下,无需将其实现为用户创建的上下文变量,但在后台很容易更改为它;例如一些 foo varchar2bar number 变量)

    用法

    select ctx.foo from dual                                                 -- => null (init)
    select ctx.foo('a') from dual                                            -- => 'a'
    select ctx.foo('b') from dual ; select ctx.foo from dual                 -- => 'b', 'b'
    

    .

    -- (optimizer should cause the subquerys unselected columns not to be executed:)
    select 'ups' from (select ctx.foo('a') from dual) ; select ctx.foo from dual   -- => null
    
    select ctx.bar(1.5) from dual ; select ctx.bar from dual                 -- => 1.5,  1.5
    -- ...
    

    包头

    create or replace package  ctx  as
    
      -- select ctx.foo from dual                                            -- => null (init)
      -- select ctx.foo('a') from dual                                       -- => 'a'
      -- select ctx.foo('b') from dual ; select ctx.foo from dual            -- => 'b', 'b'
      -- (optimizer should cause the subquerys unselected columns not to be executed:)
      -- select 'ups' from (select ctx.foo('a') from dual) ; select ctx.foo from dual
        -- => null
      -- parallel_enable for queries since it should not change inside of them
      function foo(  set varchar2 := null  ) return varchar2  parallel_enable;
    
      -- (samples like in foo above as executable test comments like in foo above skipped for 
      -- brevity)
      function bar(  set number := null  ) return  number  parallel_enable;
    
    end;
    

    包体

    create or replace package body  ctx  as
    
      foo_  varchar2(30);  -- e.g. 'blabla'
      bar_  number;
    
    
      -- internal helper function for varchars
      function set_if_not_null( ref  in out  varchar2,  val  varchar2  ) return varchar2 as 
      begin
        if  val is not null  then  ref := val;  end if;
        return ref ;
      end;
    
    
      -- internal helper function for numbers
      function set_if_not_null( ref  in out  number,  val number  ) return  number  as begin
        if  val is not null  then  ref := val;  end if;
        return ref ;
      end;
    
    
      -- (same test comments like in foo above skipped for brevity)      
      function foo(  set varchar2 := null  ) return varchar2  parallel_enable as begin
        return set_if_not_null(  foo_,  set  ) ;
      end;
    
    
      -- (same test comments like in foo above skipped for brevity)      
      function bar(  set number := null  ) return  number  parallel_enable as begin
        return set_if_not_null(  bar_,  set  ) ;
      end;
    
    end;
    

    如果您知道变量 (foo) 可能会在单个查询中发生变化,请移除 parallel_enable,否则如果查询是可并行化的,它应该会更高效。

    根据需要,当然可以添加一些foo_reset() 将其设置为空等。

    【讨论】:

      猜你喜欢
      • 2012-01-18
      • 2021-07-03
      • 2020-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-07
      相关资源
      最近更新 更多