Oracle PL/SQL - 取消引用字符串作为变量
Oracle PL/SQL - Dereference a string as a variable
是否可以在 PL/SQL 中取消引用字符串作为变量?
我正在寻找这样的东西:
declare
my_var CONSTANT varchar2(50) := 'test';
my_var_ref CONSTANT varchar2(50) := 'my_var';
begin
-- This of course doesn't work, it's just to illustrate what I'm looking for:
DBMS_OUTPUT.PUT_LINE(&my_var_ref) -- Prints test
end;
将名称作为过程参数传递:
declare
my_var CONSTANT varchar2(50) := 'test';
my_var_ref CONSTANT varchar2(50) := 'my_var';
begin
my_func(&my_var_ref) -- Pass my_var instead of my_var_ref
end;
[TL;DR] 不,您不能取消引用 PL/SQL 变量。但是,另一种选择可能是使用关联数组。
如果您尝试使用 EXECUTE IMMEDIATE
取消引用它,那么正在动态评估的 PL/SQL 块不知道来自调用块的上下文,因此无法获得取消引用变量的值。
例如:
DECLARE
my_var CONSTANT varchar2(50) := 'test';
my_var_ref CONSTANT varchar2(50) := 'my_var';
value VARCHAR2(50);
plsql_block VARCHAR2(100) := 'BEGIN :value := ' || my_var_ref || '; END;';
BEGIN
DBMS_OUTPUT.PUT_LINE( plsql_block );
EXECUTE IMMEDIATE plsql_block USING IN OUT value;
DBMS_OUTPUT.PUT_LINE( value );
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE( SQLERRM );
END;
/
输出:
BEGIN :value := my_var; END;
ORA-06550: line 1, column 17:
PLS-00201: identifier 'MY_VAR' must be declared
它获得了正确的变量名,但该变量未在 PL/SQL 块的动态评估发生的上下文中定义,因此它不起作用。
但是,如果您尝试传入变量的值(而不是尝试解除对变量的引用),那么这表明,除了解除引用之外,其余代码都可以工作:
DECLARE
my_var CONSTANT varchar2(50) := 'test';
my_var_ref CONSTANT varchar2(50) := 'my_var';
value VARCHAR2(50);
plsql_block VARCHAR2(100) := 'BEGIN :value := ''' || my_var || '''; END;';
BEGIN
DBMS_OUTPUT.PUT_LINE( plsql_block );
EXECUTE IMMEDIATE plsql_block USING IN OUT value;
DBMS_OUTPUT.PUT_LINE( value );
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE( SQLERRM );
END;
/
输出:
BEGIN :value := 'test'; END;
test
但是,您可以改用 PL/SQL 关联数组:
DECLARE
TYPE MAP IS TABLE OF VARCHAR2(50) INDEX BY VARCHAR2(50);
my_var_ref CONSTANT VARCHAR2(50) := 'my_var';
v_map MAP;
BEGIN
v_map('my_var') := 'test';
DBMS_OUTPUT.PUT_LINE( v_map( my_var_ref) );
END;
/
输出:
test
db<>fiddle here
您可以使用包。
create or replace package test_pkg as
my_var1 varchar2(50);
my_var2 varchar2(50);
my_var3 varchar2(50);
procedure set_val(p_var in varchar2,
p_val in varchar2);
function get_val(p_var in varchar2)
return varchar2;
end test_pkg;
/
create or replace package body test_pkg as
procedure set_val(p_var in varchar2,
p_val in varchar2) is
begin
execute immediate 'begin
test_pkg.' || p_var || ' := :x;
end;'
using p_val;
end set_val;
function get_val(p_var in varchar2)
return varchar2 is
v_value varchar2(50);
begin
execute immediate 'begin
:x := test_pkg.' || p_var || ';
end;'
using out v_value;
return v_value;
end get_val;
end test_pkg;
/
然后
set serveroutput on
begin
for i in 1 .. 3 loop
test_pkg.set_val('my_var' || i, 'Test ' || i);
end loop;
for i in 1 .. 3 loop
dbms_output.put_line('my_var' || i || ' = ' || test_pkg.get_val('my_var' || i));
end loop;
end;
输出:
my_var1 = Test 1
my_var2 = Test 2
my_var3 = Test 3
是否可以在 PL/SQL 中取消引用字符串作为变量?
我正在寻找这样的东西:
declare
my_var CONSTANT varchar2(50) := 'test';
my_var_ref CONSTANT varchar2(50) := 'my_var';
begin
-- This of course doesn't work, it's just to illustrate what I'm looking for:
DBMS_OUTPUT.PUT_LINE(&my_var_ref) -- Prints test
end;
将名称作为过程参数传递:
declare
my_var CONSTANT varchar2(50) := 'test';
my_var_ref CONSTANT varchar2(50) := 'my_var';
begin
my_func(&my_var_ref) -- Pass my_var instead of my_var_ref
end;
[TL;DR] 不,您不能取消引用 PL/SQL 变量。但是,另一种选择可能是使用关联数组。
如果您尝试使用 EXECUTE IMMEDIATE
取消引用它,那么正在动态评估的 PL/SQL 块不知道来自调用块的上下文,因此无法获得取消引用变量的值。
例如:
DECLARE
my_var CONSTANT varchar2(50) := 'test';
my_var_ref CONSTANT varchar2(50) := 'my_var';
value VARCHAR2(50);
plsql_block VARCHAR2(100) := 'BEGIN :value := ' || my_var_ref || '; END;';
BEGIN
DBMS_OUTPUT.PUT_LINE( plsql_block );
EXECUTE IMMEDIATE plsql_block USING IN OUT value;
DBMS_OUTPUT.PUT_LINE( value );
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE( SQLERRM );
END;
/
输出:
BEGIN :value := my_var; END; ORA-06550: line 1, column 17: PLS-00201: identifier 'MY_VAR' must be declared
它获得了正确的变量名,但该变量未在 PL/SQL 块的动态评估发生的上下文中定义,因此它不起作用。
但是,如果您尝试传入变量的值(而不是尝试解除对变量的引用),那么这表明,除了解除引用之外,其余代码都可以工作:
DECLARE
my_var CONSTANT varchar2(50) := 'test';
my_var_ref CONSTANT varchar2(50) := 'my_var';
value VARCHAR2(50);
plsql_block VARCHAR2(100) := 'BEGIN :value := ''' || my_var || '''; END;';
BEGIN
DBMS_OUTPUT.PUT_LINE( plsql_block );
EXECUTE IMMEDIATE plsql_block USING IN OUT value;
DBMS_OUTPUT.PUT_LINE( value );
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE( SQLERRM );
END;
/
输出:
BEGIN :value := 'test'; END; test
但是,您可以改用 PL/SQL 关联数组:
DECLARE
TYPE MAP IS TABLE OF VARCHAR2(50) INDEX BY VARCHAR2(50);
my_var_ref CONSTANT VARCHAR2(50) := 'my_var';
v_map MAP;
BEGIN
v_map('my_var') := 'test';
DBMS_OUTPUT.PUT_LINE( v_map( my_var_ref) );
END;
/
输出:
test
db<>fiddle here
您可以使用包。
create or replace package test_pkg as
my_var1 varchar2(50);
my_var2 varchar2(50);
my_var3 varchar2(50);
procedure set_val(p_var in varchar2,
p_val in varchar2);
function get_val(p_var in varchar2)
return varchar2;
end test_pkg;
/
create or replace package body test_pkg as
procedure set_val(p_var in varchar2,
p_val in varchar2) is
begin
execute immediate 'begin
test_pkg.' || p_var || ' := :x;
end;'
using p_val;
end set_val;
function get_val(p_var in varchar2)
return varchar2 is
v_value varchar2(50);
begin
execute immediate 'begin
:x := test_pkg.' || p_var || ';
end;'
using out v_value;
return v_value;
end get_val;
end test_pkg;
/
然后
set serveroutput on
begin
for i in 1 .. 3 loop
test_pkg.set_val('my_var' || i, 'Test ' || i);
end loop;
for i in 1 .. 3 loop
dbms_output.put_line('my_var' || i || ' = ' || test_pkg.get_val('my_var' || i));
end loop;
end;
输出:
my_var1 = Test 1
my_var2 = Test 2
my_var3 = Test 3