PL/SQLでセッション変数を宣言するにはどうすればよいですか?データベース自体に格納しなくても、セッションの間だけ持続するものですか?
「ユーザー作成コンテキスト」を使用して、セッション内の複数のユニット間で共有されるデータを保存できます。
まず、コンテキストを作成します。
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 を参照してください。
パッケージレベル変数を作成します。これは最小限の例です。
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;
短いが直感的な構文を使用するのが好きなので、たとえば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などに設定することもできます。