PL / SQL: как объявить переменные сеанса? - PullRequest
17 голосов
/ 19 ноября 2008

Как объявить переменную сеанса в PL / SQL - переменную, которая будет сохраняться только в течение сеанса, без необходимости сохранять ее в самой базе данных?

Ответы [ 3 ]

14 голосов
/ 19 ноября 2008

Вы можете использовать «пользовательский контекст» для хранения данных, совместно используемых несколькими единицами в течение сеанса.

Сначала создайте контекст:

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

13 голосов
/ 19 ноября 2008

Вы создаете переменную уровня пакета. Это минимальный пример:

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 ошибки. Каждый сеанс базы данных будет иметь свое собственное значение для. Вы можете попробовать это с:

SELECT my_package.get_a FROM DUAL;
0 голосов
/ 25 марта 2019

Мне нравится использовать короткий, но интуитивно понятный синтаксис и, таким образом, можно создать, например, некоторый ctx пакет , который просто предоставляет одну функцию для установки и получения глобальных «переменных» .
(действительно только для текущего сеанса; в моем случае нет необходимости реализовывать его как переменные контекста, созданные пользователем, но его легко заменить на него; пример с некоторыми foo varchar2 и bar 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(), чтобы установить его на ноль и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...