18

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

4

3 回答 3

15

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

首先,创建一个上下文:

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

于 2008-11-19T18:08:10.250 回答
14

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

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;
于 2008-11-19T09:51:30.080 回答
0

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

用法

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) 可能会在单个查询中发生变化,则可以使用 removeparallel_enable,否则如果查询是可并行化的,那么它的性能应该更高。

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

于 2019-03-25T08:42:04.547 回答