web-dev-qa-db-ja.com

PL / SQL:セッション変数を宣言するにはどうすればよいですか?

PL/SQLでセッション変数を宣言するにはどうすればよいですか?データベース自体に格納しなくても、セッションの間だけ持続するものですか?

17
user38871

「ユーザー作成コンテキスト」を使用して、セッション内の複数のユニット間で共有されるデータを保存できます。

まず、コンテキストを作成します。

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 を参照してください。

14
user34850

パッケージレベル変数を作成します。これは最小限の例です。

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;
13
WW.

短いが直感的な構文を使用するのが好きなので、たとえばsome ctx packageこれはいくつかのグローバル「変数」を設定および取得するための1つの関数を提供します。
(現在のセッションでのみ有効です。私の場合、ユーザーが作成したコンテキスト変数として実装する必要はありませんが、内部で簡単に変更できます。たとえば、いくつかの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()を追加してnullなどに設定することもできます。

0