Я ожидал, что в следующем коде переменные x и y относятся к одному и тому же объекту вложенной таблицы, но выражение y = x, похоже, создает пустую таблицу в y. Таким образом, результат неожиданно оказался «Нет: a c» (хотя я ожидал «Да: a b c» ). Что мне делать в PL / SQL, чтобы y ссылался на тот же объект вложенной таблицы, что и x.

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;

Можно ли (передать вложенную таблицу по ссылке, а не по значению) на PL / SQL или это принципиально невозможно? Существуют ли какие-либо альтернативы в языке для решения проблемы?

0
user4298563 13 Мар 2015 в 09:06

2 ответа

Лучший ответ

PL / SQL не имеет ссылок (но в одном месте мы увидим позже), поэтому, по сути, то, что вы просите, невозможно в PL / SQL. Однако я не понимаю, как это может быть проблемой.

В вашем примере x и y - две разные переменные одного типа (коллекция вложенных таблиц), x := y - присвоение переменной (глубокая копия), x = y представляет собой сравнение. См. Также, например, Присвоение значений переменным.

Я предполагаю, что у вас есть опыт программирования с некоторыми другими языками, и вы пытаетесь применить здесь какую-то другую языковую парадигму. У вас также может быть проблема XY.

Одна альтернатива - использовать две разные индексные переменные для доступа к коллекции. Это может или не может подойти для вашего случая:

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;
/

Но обратите внимание, что изменения в коллекции сделают недействительными индексные переменные (поэтому я объявил постоянную коллекцию).

При работе с вложенными таблицами также проверьте условия мультимножества SQL которые обеспечивают мощные манипуляции.

Единственное место с эталонной семантикой - это параметры подпрограммы где разные режимы параметров (IN, OUT или IN OUT) имеют разную семантику (передача по значению или передача по ссылке). Но даже там решение принимает компилятор / среда выполнения PL / SQL - у программиста нет особого контроля.

1
Community 20 Мар 2017 в 10:29

Таким образом, на удивление выводится «Нет: a c» (хотя я ожидал «Да: a b c»).

Ваше ожидание неверно. Поскольку два массива имеют разные значения.

Посмотрим пошагово:

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

Итак, x имеет значение a .

у: = х;

x копируется в y , поэтому y имеет значение a .

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

Теперь у y есть a и b .

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

Теперь у x есть a и c .

В заключение,

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>

Итак, X и Y не равны.

Чтобы сделать их равными, установите 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>
0
Lalit Kumar B 13 Мар 2015 в 06:34