Зміна з’єднання, Інші СУБД, Бази даних, статті

Ця стаття присвячена “хитрим” операторам UPDATE, Що змінює дані в одній таблиці на основі даних з іншої. Попутно обговорюються причини виникнення помилки ORA-01779 при виконанні таких дій шляхом зміни з’єднання. За мотивами чергового відповіді Тома Кайта.

Оператор UPDATE і NULL-значення


Том,

При зміні стовпця за допомогою оператора update, Значення деяких записів (які не треба міняти) змінюється на NULL. Я використовую наступний оператор:

update    table    name B
set columnname =
( select value
from lookup O
where B.keyname = O.keyname
and O.Othercolumn = Other_value);

В результаті виконуються всі необхідні зміни, але змінюються і записи, які не треба міняти: вони отримують значення Null. Чи можна цього уникнути, оскільки нам треба часто змінювати записи, але не все відразу.


Чи немає способу змінити тільки ті записи, які потрібно, і не скинути значення в інших записах в Null?


Відповідь Тома Кайта


Є як мінімум 2 способи правильно виконати такого роду корельованих зміна. Я покажу свій улюблений метод (зміна з’єднання) і інший метод, який буде працювати якщо не можна задати обмеження унікальності по LOOKUP(keyname) (Що необхідно для успішного зміни з’єднання).


Розглянемо наступні тестові таблиці:

scott@ORA734.WORLD> create table name
2 ( keyname int,
3 columnName varchar2(25)
4 )
5 /
Table created.
scott@ORA734.WORLD> create table lookup
2 ( keyname int PRIMARY KEY,
3 value varchar2(25),
4 otherColumn int
5 )
6 /
Table created.
scott@ORA734.WORLD> insert into name values ( 100, “Original Data” );
1 row created.
scott@ORA734.WORLD> insert into name values ( 200, “Original Data” );
1 row created.
scott@ORA734.WORLD> insert into lookup values ( 100, “New Data”, 1 );
1 row created.
scott@ORA734.WORLD> commit;
Commit complete.

А ось параметр “other_value“, Який ви використовуєте в своєму операторі update

scott@ORA734.WORLD> variable other_value number
scott@ORA734.WORLD> exec :other_value := 1
PL/SQL procedure successfully completed.
scott@ORA734.WORLD> select * from name;
KEYNAME COLUMNNAME
———- ————————-
100 Original Data
200 Original Data

Далі ми змінюємо з’єднання. Можна змінювати значення стовпців тільки в одній з таблиць, а інші таблиці, які ми не змінюємо, повинні бути “захищені ключем” – ми повинні мати гарантію, що при з’єднанні NAME з другої таблицею буде повернуто не більше одного запису. Для цього стовпець keyname в таблиці LOOKUP повинен бути або первинним ключем, або бути пов’язаним обмеженням унікальності …

scott@ORA734.WORLD> update
2 ( select columnName, value
3 from name, lookup
4 where name.keyname = lookup.keyname
5 and lookup.otherColumn = :other_value )
6 set columnName = value
7 /
1 row updated.
scott@ORA734.WORLD> select * from name;
KEYNAME COLUMNNAME
———- ————————-
100 New Data
200 Original Data

Зверніть увагу, змінилася тільки цікавить нас рядок – інші дані не порушені …

scott@ORA734.WORLD> rollback;
Rollback complete.
scott@ORA734.WORLD> select * from name;
KEYNAME COLUMNNAME
———- ————————-
100 Original Data
200 Original Data

Наступний спосіб спрацює без жодних обмежень – не потрібно первинного ключа млм обмеження унікальності для таблиці lookup (Але краще точно знати, що підзапит поверне 0 або 1 запис!).


Оператор дуже схожий на ваш update, Але має конструкцію where, Щоб змінювалися лише рядки, для яких є відповідники …

scott@ORA734.WORLD> update name
2 set columnName = ( select value
3 from lookup
4 where lookup.keyname = name.keyname
5 and otherColumn = :other_value )
6 where exists ( select value
7 from lookup
8 where lookup.keyname = name.keyname
9 and otherColumn = :other_value )
10 /
1 row updated.
scott@ORA734.WORLD> select * from name;
KEYNAME COLUMNNAME
———- ————————-
100 New Data
200 Original Data

А чи можна домогтися того ж для декількох стовпців?


Том,

Мені не вдалося зробити наступне. Я створив дві таблиці t і t1 за допомогою select * from user_objects. У таблицях t і t1 – По 117 записів. Потім я взяв один object_name(PRIMARY_SALESFORE) в таблиці t і змінив три записи – object_type, object_id і created.

ADHOC@VOYAGER> select t.object_id,t1.object_id,t.object_type,t1.object_type,
2 t.created,t1.created
3 from t,t1
4 where t1.object_name=t.object_name
5 and t.object_name=”PRIMARY_SALESFORCE”;
OBJECT_ID OBJECT_ID OBJECT_TYPE OBJECT_TYPE CREATED CREATED
——— ——— ————- ————- ——— ———
2222 17927 ORATAB TABLE 02-APR-02 01-APR-02

Тепер при спробі змінити ці три поля в таблиці t на основі t1 я отримую наступне повідомлення про помилку. Що я роблю не так?

1  update
2 (select t.object_id,t1.object_id,t.object_type,t1.object_type,
3 t.created,t1.created
4 from t,t1
5 where t1.object_name=t.object_name
6 and t.object_name=”PRIMARY_SALESFORCE”)
7 set t.object_id=t1.object_id,
8 t.object_type=t1.object_type,
9* t.created=t1.created
ADHOC@VOYAGER> /
update
*
ERROR at line 1:
ORA-00904: invalid column name

При спробі змінити всього один стовпець в T я теж отримую повідомлення про помилку:

ADHOC@VOYAGER> update
2 (select t.object_id toid,t1.object_id t1oid
3 from t,t1
4 where t.object_name=t1.object_name
5 and upper(t.object_name)=”PRIMARY_SALESFORCE”)
6 set toid=t1oid;
update
*
ERROR at line 1:
ORA-01779: cannot modify a column which maps to a non key-preserved table

Відповідь Тома Кайта


Таблиці T і T1 “Невидимі” за межами підставляємо подання (inline view). Ви це виправили, додавши псевдоніми toid, t1oid.


Що стосується другої помилки, будь ласка, перечитайте представлений вище відповідь. ТРЕБА, щоб стовпець object_id таблиці T1 був пов’язаний обмеженням первинного ключа / унікальності, щоб кожен рядок таблиці T з’єднувалася НЕ БІЛЬШЕ, ніж з одним рядком таблиці T1.


Нехай в таблиці T є:

OBJECT_NAME          OBJECT_ID
————– —————-
ABC xxxx

А в таблиці T1:

OBJECT_NAME          OBJECT_ID
—————- ——————
ABC 123
ABC 456

що повинно бути в результаті:

ADHOC@VOYAGER> update
2 (select t.object_id toid,t1.object_id t1oid
3 from t,t1
4 where t.object_name=t1.object_name
5 and upper(t.object_name)=”PRIMARY_SALESFORCE”)
6 set toid=t1oid;

чи треба при з’єднанні брати 123 або 456, і в яких випадках? Оскільки результат цієї зміни на 100% неоднозначно, ми його не допускаємо. Необхідно гарантувати захист ключем за допомогою обмеження первинного ключа / унікальності.


Відповідний індекс у будь-якому випадку потрібен з міркувань продуктивності.


Коментар читача від 2 квітня 2002


Спасибі, Том. Я знав, що якщо ще раз (уважно) перечитаю твою відповідь, то зможу знайти помилку в SQL-операторі. Але, в будь-якому випадку, не міг би ти допомогти мені домогтися бажаної мети – змінити три стовпці з іншої таблиці, що має один співпадаючий стовпець (object_name), Унікальний, але не є первинним ключем.


Відповідь Тома Кайта

update t
set ( f1, f2, f3 ) =
( select a, b, c from t2 where t2.some_field = t.some_field )
where exists ( select a, b, c from t2 where t2.some_field = t.some_field )
/

Цей запит дозволить вирішити вашу проблему. Якщо не можна задати обмеження унікальності (яке потрібно ТЕОРЕТИЧНО, навіть якщо не буде потрібно практично – якщо значення в стовпці some_field таблиці t2 виявляться НЕ унікальними, представлений запит закінчиться повідомленням про помилку “підзапит повернув більше одного рядка”, тому що оператор update буде неоднозначно)


Хороший прийом. Коментар читача від 9 квітня 2002


Спасибі за прекрасний сайт. Я намагаюся змінити таблицю на основі певної інформації в тій же таблиці. Запит виглядає наступним чином:

DECLARE
CURSOR c1 IS SELECT ROWID FROM
siebel.s_synd_data
where
WHERE
ROW_ID LIKE “DDM%”
AND DATA_SRC_CD = “DECPRF”
and POSITION_ID IS NULL;
begin
for cur in c1 loop
UPDATE SIEBEL.S_SYND_DATA A
SET A.POSITION_ID = (SELECT B.ROW_ID FROM SIEBEL.S_POSTN B,
SIEBEL.S_ASGN_GRP C
WHERE A.TERR_ID = C.ROW_ID
AND SUBSTR(C.NAME, 1, 5) // “00D” = B.NAME)
where rowid=cur.rowid;
if mod(c1%rowcount,50000)=0 then
commit;
end if;
end loop;
commit;
end ;

Передбачається, що умові WHERE курсора C1 буде задовольняти 9000000 рядків. Мій АБД каже, що транзакція буде зафіксована тільки після зміни 9000000 рядків, і мені треба фіксувати її після кожних 50000 – чи правильно це?


Що можна зробити, щоб ця зміна виконувалося швидше – я знаю, що ти ненавидиш такі питання, якщо за ними не стоять певні критерії, але що, якщо я створю індекс (за функцією)?


Відповідь Тома Кайта


Я особисто робив би так:

update s_synd_data a – вибачте, я не можу змусити себе набрати sie ….
set a.position_id = ( select b.row_id
from s_postn b, s_asng_grp c
where c.row_id = a.terr_id
and b.name = substr(c.name,1,5) // “00D” )
where row_id like “DDM%”
and data_src_cd = “DECPRF”
and position_id is null;

Якби по стовпцю position_id був індекс, я б його видалив, виконав зміна і перестворювати індекс без можливості відновлення і з розпаралелюванням.


Перш ніж ви скажете: “але там же 9000000 рядків – треба фіксувати по частинах”, я відповім – ні в якому разі. Перевірте тільки, що виділено достатньо сегментів відкоту (інакше, при використанні вашого підходу, РАНО ЧИ ПІЗНО, ви отримаєте повідомлення про помилку ORA-01555 – Пошукайте на сайті обговорення по слову 01555 або 1555 і зрозумієте, що я маю на увазі).


Буде потрібно не так вже й багато місця в сегментах відкату, як може здатися. Процедурний код, начебто вашого:



У своїй системі я тільки що змінив 1099008 рядків:

ops$tkyte@ORA817DEV.US.ORACLE.COM> update big_table set owner = lower(owner);
Elapsed: 00:08:38.66
ops$tkyte@ORA817DEV.US.ORACLE.COM> select used_ublk from v$transaction;
USED_UBLK
———-
13002
Elapsed: 00:00:00.01
ops$tkyte@ORA817DEV.US.ORACLE.COM> select 13002*8/1024 from dual;
13002*8/1024
————
101.578125
Elapsed: 00:00:00.01
ops$tkyte@ORA817DEV.US.ORACLE.COM> select count(*) from big_table;
COUNT(*)
———-
1099008
Elapsed: 00:00:02.41

для цього було потрібно близько 100 Мбайт в сегменті відкату. Вам слід очікувати порядку гігабайти. Я б просто переконався (за допомогою АБД), що стільки місця є, використовував би оператор set transaction use rollback segment при необхідності (можна просто створити тимчасовий сегмент для цього оператора update в каталозі /tmp, Наприклад, і потім його видалити). Виконайте update. Цього достатньо.


Менше думати, менше робити, менше ймовірність помилки …


Коментар читача від 30 квітня 2002


Шановний Том …

В якій версії Oracle з’явилася можливість виконувати “зміна з’єднання”? Я завжди використовував для таких запитів другий варіант, з конструкцією EXISTS. Завжди здавалося смішним, що припадає один і той же підзапит вводити двічі.


Тобі треба написати книжку про хитрих прийомах в Oracle SQL.


Відповідь Тома Кайта


Упевнений, що ця можливість з’явилася у версії 7.3

ops$tkyte@ORA734.WORLD> create table t1 ( x int primary key, y int );
Table created.
ops$tkyte@ORA734.WORLD> create table t2 ( x int, y int );
Table created.
ops$tkyte@ORA734.WORLD> insert into t1 values ( 1, 1 );
1 row created.
ops$tkyte@ORA734.WORLD> insert into t1 values ( 2, 2 );
1 row created.
ops$tkyte@ORA734.WORLD> insert into t2 values ( 2, null );
1 row created.
ops$tkyte@ORA734.WORLD> insert into t2 values ( 3, null );
1 row created.
ops$tkyte@ORA734.WORLD> update ( select t1.y t1_y, t2.y t2_y
2 from t1, t2
3 where t1.x = t2.x )
4 set t2_y = t1_y
5 /
1 row updated.
ops$tkyte@ORA734.WORLD> select * from t2;
X Y
———- ———-
2 2
3

Паралельні оператори ЯМД і зміна уявлення з з’єднанням

ADHOC@VOYAGER> update
2 (select t.object_id toid,t1.object_id t1oid
3 from t,t1
4 where t.object_name=t1.object_name
5 and upper(t.object_name)=”PRIMARY_SALESFORCE”)
6 set toid=t1oid;

У представленому вище запиті, який демонструє зміну подання із з’єднанням, мене цікавить, чи виконується ця зміна паралельно, якщо таблиця t фрагментована і виконаний оператор alter session enable parallel dml. Я використовую аналогічний оператор update і з’ясував, що кращим планом виконання оператора select буде повний перегляд обох таблиць і соедітненіе хешування.


Відповідь Тома Кайта


Якщо задоволені всі інші критерії (включено розпаралелювання, таблиці допускають “розпаралелювання”) – має виконуватися паралельно.


Зміна буде виконуватися за фрагментами таблиці T, З повним переглядом кожного фрагмента T і з’єднанням його з таблицею T1 після фільтрації по умові upper(t.object_name).


Один із способів переконатися в цьому – виконати зміну, а потім – оператор select * from t where rownum = 1; Якщо цей оператор спрацює, зміна не распараллелівать, а якщо ні – було виконано паралельно. Виконайте Commit і зможете вибирати дані.


Чи можна це зробити, якщо задіяно більше двох таблиць?


Я робив це, коли в поєднанні задіяно дві таблиці.


Чи можна це зробити, якщо необхідно змінити стовпець таблиці A у відповідності до значень стовпця в таблиці C. Таблиці пов’язані так: A -> B -> C, Де A є головною для всіх, а B – Головної для C?


Відповідь Тома Кайта


Ай-я-яй, такий простий приклад – ви ж все вже вказали – і не спробувати зробити … Гаразд.


Відповідь – так, якщо дотримується “захист ключем”, іншими словами, кожен рядок таблиці A з’явиться в результаті з’єднання НЕ БІЛЬШЕ ОДНОГО РАЗА. В іншому випадку – ні.


Розглянемо простий приклад:

ops$tkyte@ORA920.LOCALHOSTgt; create table a ( x int primary key, y int );
Table created.
ops$tkyte@ORA920.LOCALHOST> create table b ( x references a primary key );
Table created.
ops$tkyte@ORA920.LOCALHOST> create table c ( x references b primary key, y int );
Table created.
ops$tkyte@ORA920.LOCALHOST> insert into a values ( 1, null );
1 row created.
ops$tkyte@ORA920.LOCALHOST> insert into a values ( 2, null );
1 row created.
ops$tkyte@ORA920.LOCALHOST> insert into b values ( 1 );
1 row created.
ops$tkyte@ORA920.LOCALHOST> insert into c values ( 1, 100 );
1 row created.
ops$tkyte@ORA920.LOCALHOST> select * from a;
X Y
———- ———-
1
2
ops$tkyte@ORA920.LOCALHOST> update ( select a.y a_y, c.y c_y
2 from a, b, c
3 where a.x = b.x and b.x = c.x )
4 set a_y = c_y;
1 row updated.
ops$tkyte@ORA920.LOCALHOST> select * from a;
X Y
———- ———-
1 100
2

Блокування. Коментар читача від 2 жовтня 2002


Том,

В разі:

update
( select columnName, value
from name, lookup
where name.keyname = lookup.keyname
and lookup.otherColumn = :other_value )
set columnName = value
/

чи будуть обидві таблиці, name і lookup, Заблоковані по ходу зміни?


Відповідь Тома Кайта

ops$tkyte@ORA920.LOCALHOST> alter table emp add dname varchar2(30);
Table altered.
ops$tkyte@ORA920.LOCALHOST> update ( select emp.dname edname, dept.dname ddname
2 from emp, dept
3 where emp.deptno = dept.deptno )
4 set edname = ddname;
14 rows updated.
ops$tkyte@ORA920.LOCALHOST> select type, id1, (select object_name from
user_objects where object_id = id1) oname
2 from v$lock
3 where sid = (select sid from v$mystat where rownum=1)
4 and type = “TM”
5 /
TY ID1 ONAME
— ———- ——————–
TM 31715 EMP

Блокуються лише рядки таблиці, яку ви змінюєте.


Коментар читача від 29 січня 2003

scott@ORA734.WORLD> update
2 ( select columnName, value
3 from name, lookup
4 where name.keyname = lookup.keyname
5 and lookup.otherColumn = :other_value )
6 set columnName = value
7 /
1 row updated.
scott@ORA734.WORLD> update name
2 set columnName = ( select value
3 from lookup
4 where lookup.keyname = name.keyname
5 and otherColumn = :other_value )
6 where exists ( select value
7 from lookup
8 where lookup.keyname = name.keyname
9 and otherColumn = :other_value )
10 /
1 row updated.

Том,

який з цих двох запитів краще з точки зору продуктивності? Я припускаю, що перший, але сумніваюся. Якщо я помиляюся, то чому?


Відповідь Тома Кайта


Обидва погані …


Ні, перший краще


Хоча, постійте, другий краще


Обидва можуть працювати швидко, я думаю …


Їх продуктивність буде залежати від використовуваного оптимізатора, актуальності статистичної інформації, і т.п.


У загальному випадку, якщо “NAME“- Дуже маленька таблиця, а”LOOKUP“- Дуже велика, (але проіндексована по keyname/othercolumn) – Оператор з where exists цілком можна використовувати.


Але звичайно краще змінювати з’єднання.


Зміна головної таблиці на основі підпорядкованої (підпорядкована – з складовим ключем)


Не міг би ти допомогти мені зробити те, що я намагаюся – змінити 2 або більше стовпця головної таблиці на основі даних в підлеглої, у якої первинний ключ – складової.


Приклад:

Таблиця: Food
(food_id number primary key
food_name varchar2(100)
calorie number
fibre number
total_fat number
)
Приклад даних у таблиці Food:
Food_id food_name calorie fibre total_fat
1 apple null null null
2 beer null null null
Таблиця: Food_Portion
(food_id number
portion_id number
qty number
weight number
calorie number
fibre number
total_fat number
)
food_id + portion_id – первинний ключ
Приклад даних у таблиці Food_Portion:
Food_id Portion_ID qty weight calorie fibre total_fat
1 1 1 10 10 3 3
1 2 2 15 20 5 2
1 3 100 100 60 10 9
2 1 1 10 5 0 0
2 2 .5 6 4 0 0
2 3 100 100 40 0 10

В результаті зміни треба встановити значення стовпців calorie, fibre і total_fat в таблиці food_table рівними значенням в таблиці food_portion, Де food_portion.qty = 100 і food_portion.weight = 100


Гарантується, що для кожного food_id в таблиці food_portion буде тільки один рядок з qty = 100 і weight = 100 (Тобто оператор select food_id from food_portion where qty = 100 and weight = 100 поверне рівно один рядок для кожного значення food_id)


Я виконував наступний оператор update:

update ( select a1, b1 from a, b where a.id = b.id )
set a1 = b1 (this one I haven”t tried)

Але отримав повідомлення про помилку “ORA-01779: cannot modify a column which maps to a non key-preserved table”


Потім я спробував виконати:

update t
set ( f1, f2, f3 ) =
( select a, b, c from t2 where t2.some_field = t.some_field )
where exists ( select a, b, c from t2 where t2.some_field = t.some_field )

update a
set a1 = ( select b1 from b where b.id = a.id )
where a.id in ( select id from b )


І обидва оператора повернули повідомлення про помилку ORA-01427: single-row subquery returns more than one row


Мене цікавить, чи можна виконати таку зміну, не використовуючи PL / SQL?


Відповідь Тома Кайта


Якщо ви вказуєте:

where t2.some_field = t.some_field )

І отримуєте:


ORA-01427: single-row subquery returns more than one row


Значить, припущення про єдиності рядки для кожного food_id не виправдалося.


Але, в будь-якому випадку, якщо запит:

select food_id
from food_portion
where qty = 100 and weight = 100
group by food_id
having count(*) > 1;

повертає НУЛЬ рядків (немає дубльованих значень!), то:

ops$tkyte@ORA817DEV> update food
2 set (calorie,fibre,total_fat) =
3 (select calorie,fibre,total_fat
4 from food_portion fp
5 where fp.food_id = food.food_id
6 and fp.qty = 100
7 and fp.weight = 100 )
8 where exists
9 (select calorie,fibre,total_fat
10 from food_portion fp
11 where fp.food_id = food.food_id
12 and fp.qty = 100
13 and fp.weight = 100 )
14 /

Виконує відповідну зміну.


Дуже корисний приклад


Після того, як побачив спосіб зміни з’єднання, виявив, що він добре підходить для зміни одного джерела даних з переглядом попередніх і остаточних значень:

scott@MSORA920>create table dept_demo as select * from dept;
Table created.
scott@MSORA920>SELECT deptno, dname, INITCAP(dname) Iname, loc, INITCAP(loc)
Iloc FROM dept_demo;
DEPTNO DNAME INAME LOC ILOC
———- ————– ————– ————- ————-
10 ACCOUNTING Accounting NEW YORK New York
20 RESEARCH Research DALLAS Dallas
30 SALES Sales CHICAGO Chicago
40 OPERATIONS Operations BOSTON Boston
scott@MSORA920>edit
Wrote file afiedt.buf
1 UPDATE(
2 SELECT deptno, dname, INITCAP(dname) Iname, loc, INITCAP(loc) Iloc FROM
dept_demo
3* ) SET dname = Iname, loc = Iloc
scott@MSORA920>/
4 rows updated.
scott@MSORA920>edit
Wrote file afiedt.buf
1* SELECT deptno, dname, INITCAP(dname) Iname, loc, INITCAP(loc) Iloc FROM
dept_demo
scott@MSORA920>/
DEPTNO DNAME INAME LOC ILOC
———- ————– ————– ————- ————-
10 Accounting Accounting New York New York
20 Research Research Dallas Dallas
30 Sales Sales Chicago Chicago
40 Operations Operations Boston Boston
scott@MSORA920>

Спасибі 🙂


Коментар читача від 1 травня 2003


Том,

Якщо у твоєму вихідному прикладі замість:

Update…
SET columnName = Value;

Написати:

Update…
SET Value = columnName;

Я отримую повідомлення про помилку “ORA-01779: cannot modify a column which maps to a non key-preserved table“(Див. нижче).


Розмі в запиті columnName не повертає теж всього один запис? Чому так не спрацьовує?

SQL> CREATE TABLE name (
2 keyname INT,
3 columnName VARCHAR2(25)
4 );
Table created.
SQL> CREATE TABLE lookup (
2 keyname INT PRIMARY KEY,
3 value VARCHAR2(25),
4 otherColumn INT
5 );
Table created.
SQL> insert into name values ( 100, “Original Data” );
1 row created.
SQL> insert into name values ( 200, “Original Data” );
1 row created.
SQL> insert into lookup values ( 100, “New Data”, 1 );
1 row created.
SQL> commit;
Commit complete.
SQL> UPDATE (
2 SELECT a.columnName, b.value
3 FROM name a, lookup b
4 WHERE a.keyname = b.keyname AND
5 b.otherColumn = 1)
6 SET columnName = value;
1 row updated.
SQL> rollback;
Rollback complete.
SQL> UPDATE (
2 SELECT a.columnName, b.value
3 FROM name a, lookup b
4 WHERE a.keyname = b.keyname AND
5 b.otherColumn = 1)
6 SET value = columnName;
SET value = columnName
*
ERROR at line 6:
ORA-01779: cannot modify a column which maps to a non key-preserved table

Відповідь Тома Кайта

SQL> CREATE TABLE name (
2 keyname INT,
3 columnName VARCHAR2(25)
4 );
Table created.
SQL> CREATE TABLE lookup (
2 keyname INT PRIMARY KEY,
3 value VARCHAR2(25),
4 otherColumn INT
5 );
insert into name values ( 1, “x” );
insert into name values ( 1, “y” );
insert into lookup values ( 1, null, null );

А тепер, який результат має вийти після зміни:

SQL> UPDATE (
2 SELECT a.columnName, b.value
3 FROM name a, lookup b
4 WHERE a.keyname = b.keyname AND
5 b.otherColumn = 1)
6 SET value = columnName;

Стовпець value буде мати значення x або y?


Щоб позбутися від двозначності, необхідний первинний ключ по стовпцях таблиць “lookup“, За якими виконується з’єднання – у вас його немає.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*