Ошибка таблицы без сохранения ключа для обновления с уникальными данными - PullRequest
0 голосов
/ 03 июля 2018

Я запутался в обновлении представления сохраненных ключей в Oracle (и вообще); когда выполняется обновление с использованием выбора с объединением, ожидается ли сохраненное свойство ключа для обновляемой таблицы или для встроенного оператора выбора.

В следующем примере:

SQL> create table tabX (x1 number, x2 number);

Table created.

SQL>  create table tabY (y1 number, y2 number);

Table created.

SQL> insert into tabx values (1,11);

1 row created.

SQL> insert into tabx values (2,12);

1 row created.

SQL> insert into taby values(1,21);

1 row created.

SQL>  insert into taby values(2,22);

1 row created.

SQL> commit;

Commit complete.

вывод select является уникальным, но обновление все равно не выполняется. В выборе и обновлении нет двусмысленности или дублирования - так почему же это не получается?

SQL> select x2,y2 from tabx,taby where tabx.x1=taby.y1;

        X2         Y2
---------- ----------
        11         21
        12         22

SQL> update (select x2,y2 from tabx,taby where tabx.x1=taby.y1) set x2=y2;
update (select x2,y2 from tabx,taby where tabx.x1=taby.y1) set x2=y2
                                                           *
ERROR at line 1:
ORA-01779: cannot modify a column which maps to a non key-preserved table

Ответы [ 2 ]

0 голосов
/ 03 июля 2018

Если вы не хотите использовать ключ, как предложил AlexPoole, вы можете легко превратить его в инструкцию MERGE (это то, что мы пробуем каждый раз, когда мы встречаемся с ошибкой «без сохранения ключа» при обновлении представления) :

MERGE 
 INTO tabx
USING taby
   ON (x1 = y1)
 WHEN MATCHED THEN
   UPDATE
      SET x2 = y2
;
0 голосов
/ 03 июля 2018

Вы знаете, что дублирования нет, но когда синтаксический анализ оператора выполняется, оптимизатор не знает, что его нет, и, что более важно, не может быть , любое дублирование. Парсер смотрит на статистику, чтобы решить, как работать, но в целом не смотрит на данные. Оператор обновления может быть кэширован и использован повторно, поэтому, даже если бы он посмотрел и увидел, что сейчас нет дубликатов, данные могли бы измениться, если этот же оператор снова будет выполнен позже из кэша.

Представьте, что вы добавили дополнительную строку:

insert into taby values(2,222);

тогда ваш запрос получит:

select x2,y2 from tabx,taby where tabx.x1=taby.y1;

        X2         Y2
---------- ----------
        11         21
        12         22
        12        222

Теперь в обновлении есть два возможных значения для установки обоих значений x2=12; Должны ли они оба быть 22, или оба 222, или один из каждого? У Oracle нет возможности узнать, что правильно, и он не может выбрать, какой из первых двух вариантов следует использовать (и уж точно не может использовать третий).

Теперь это не ваша настоящая ситуация, но вы должны сказать Oracle, что ситуация не может возникнуть. Формулировка ошибки здесь подсказка; для сохранения ключа должен быть ключ. Если вы определите tabY с помощью первичного или уникального ключа:

create table tabY (y1 number primary key, y2 number);

insert into taby values(1,21);

insert into taby values(2,22);

тогда моя готовая третья вставка не разрешена, Oracle знает об этом и может применить эти знания к обновлению:

update (select x2,y2 from tabx,taby where tabx.x1=taby.y1) set x2=y2;

2 rows updated.

select x2,y2 from tabx,taby where tabx.x1=taby.y1;

        X2         Y2
---------- ----------
        21         21
        22         22

Неважно, сколько у вас строк с x1=2, вы хотите, чтобы все они были обновлены до x2=22. Так что x1 не обязательно должно быть уникальным, и вам не нужен UK / Pk для этого. Но y1 должен быть уникальным, чтобы вы знали, какое одиночное значение y2 использовать для всех из этих x1=2 строк.

Что я не понимаю, так это то, становится ли представление сохраненным на основе ключа, если включенные столбцы объявляются уникальными, или фактические значения, которые обновляются.

Это столбцы, а не значения. Но мне кажется, что я не очень хорошо объяснил, что, поскольку вы делаете set x2=y2, он может видеть, что только таблица tabx фактически обновляется; поэтому он должен иметь возможность определить, какие строки в таблице tabx затронуты, а затем он должен работать для каждой из этих строк , какой соответствует строке taby, чтобы получить y2 значения из - которые он получает из условия соединения.

Для каждого обновляемого x2 он должен идентифицировать одно значение y2 для использования, что он делает, ища строку taby, где taby.y1 - * этой строки tabx.x1 , Если в taby было (или могло быть просто) несколько строк, соответствующих этому условию, то он не знал бы, какие из этих опций использовать - 22 или 222 в моем примере. В taby должно быть одно совпадение, поэтому y1 должно быть уникальным и должно быть объявлено как уникальное через Великобританию или PK.

Может быть много разных значений x2, которые обновляются до одного и того же значения y2; Вы также можете иметь

insert into tabx values(2,13);
insert into tabx values(2,14);
etc.

и все они будут обновлены до того же значения - 22 - потому что неуникальное значение x1 во всех этих строках по-прежнему отображается в одну строку ytab с этими таблицами UK / PK через соединение состояние.

...