如何创建引用相同嵌套 table 的两个变量?

How to create two variables refering the same nested table?

我预计在下面的代码中变量 xy 引用相同的嵌套 table 对象但是表达式 y = x 似乎创建空 table在 y。所以输出是令人惊讶的'No: a c'(但是我期望'Yes: a b c')。我应该在 PL/SQL 中做什么才能让 y 引用与 x.

相同的嵌套 table 对象
declare
  type str_t is table of varchar(100);
  x str_t := str_t ();
  y str_t ;
begin 

  x.extend;  x(x.last) := 'a';

  y := x;

  y.extend;  y(y.last) := 'b';

  x.extend;  x(x.last) := 'c';

  dbms_output.put_line(case when x=y then 'Yes: ' else 'No: ' end);

  for i in x.first .. x.last
  loop       
     dbms_output.put_line(x(i));      
  end loop;

С(通过引用传递嵌套的 table - 而不是按值)写在 PL/SQL 中还是根本不可能?语言中是否存在任何替代方法来避免该问题?

So output is surprisingly 'No: a c' ( however I expected 'Yes: a b c').

你的期望是错误的。由于两个数组具有不同的值。

让我们一步步来看:

x.extend;
x(x.last) := 'a';

所以,x 的值为 a

y := x;

x 被复制到 y,所以 y 的值为 a.

y.extend;
y(y.last) := 'b';

现在,yab

x.extend;
x(x.last) := 'c';

现在,xac.

最后,

X --> a,c
Y --> a,b

让我们看看您的代码显示的输出是什么:

SQL> set serveroutput on
SQL> DECLARE
  2  type str_t
  3  IS
  4    TABLE OF VARCHAR(100);
  5    x str_t := str_t ();
  6    y str_t ;
  7  BEGIN
  8    x.extend;
  9    x(x.last) := 'a';
 10    y         := x;
 11    y.extend;
 12    y(y.last) := 'b';
 13    x.extend;
 14    x(x.LAST) := 'c';
 15    FOR i IN x.first .. x.last
 16    LOOP
 17      dbms_output.put_line('X'||'-'||x(i));
 18    END LOOP;
 19    FOR i IN y.first .. y.last
 20    LOOP
 21      dbms_output.put_line('Y'||'-'||y(i));
 22    END LOOP;
 23  END;
 24  /
X-a
X-c
Y-a
Y-b

PL/SQL procedure successfully completed.

SQL>

所以,XY 不相等。

为了使它们相等,设置Y = X:

SQL> set serveroutput on
SQL> DECLARE
  2  type str_t
  3  IS
  4    TABLE OF VARCHAR(100);
  5    x str_t := str_t ();
  6    y str_t ;
  7  BEGIN
  8    x.extend;
  9    x(x.LAST) := 'a';
 10    x.extend;
 11    x(x.last) := 'b';
 12    x.extend;
 13    x(x.LAST) := 'c';
 14    y         := x;
 15    dbms_output.put_line(case when x=y then 'Yes: ' else 'No: ' end);
 16    FOR i IN x.first .. x.last
 17    LOOP
 18      dbms_output.put_line('X'||'-'||x(i));
 19    END LOOP;
 20  END;
 21  /
Yes:
X-a
X-b
X-c

PL/SQL procedure successfully completed.

SQL>

PL/SQL 没有引用(但在一个地方我们稍后会看到)所以基本上你要问的在 PL/SQL 中是不可能的。不过,我不明白这怎么会是个问题。

在您的示例中,xy 是两个具有相同类型的不同变量(嵌套 table 集合),x := y 是一个变量赋值(深拷贝), x = y 是一个 comparison. See also e.g. Assigning Values to Variables.

我猜你有一些其他语言的编程背景,你正试图在这里应用一些其他语言范例。你也可能有一个 XY-problem.

一种替代方法是使用两个不同的索引变量来访问集合。这可能适合也可能不适合您的情况:

declare
  type str_list_t is table of varchar2(32767);
  v_foos constant str_list_t := str_list_t('a', 'b', 'c');
  -- have some business logic to get the right indices
  i pls_integer := 1;
  j pls_integer := 3;
begin
  dbms_output.put_line(v_foos(i));
  dbms_output.put_line(v_foos(j));
end;
/

但请注意,对集合的更改会使索引变量无效(这就是我声明常量集合的原因)。

当使用嵌套的 tables 时,还要检查 SQL multiset conditions 以提供强大的操作。

唯一具有引用语义的地方是 subprogram parameters,其中不同的参数模式(INOUTIN OUT)具有不同的语义(按值传递或按引用传递)。但即使在那里,决定是由 PL/SQL compiler/runtime 做出的 - 程序员没有太多控制权。