Оновіть оператор з внутрішнім приєднанням в Oracle


298

У мене є запит, який добре працює в MySQL, але коли я запускаю його в Oracle, я отримую таку помилку:

Помилка SQL: ORA-00933: Команда SQL неправильно закінчена
00933. 00000 - "Команда SQL неправильно закінчена"

Запит:

UPDATE table1
INNER JOIN table2 ON table1.value = table2.DESC
SET table1.value = table2.CODE
WHERE table1.UPDATETYPE='blah';

Коли я намагався налаштувати table2 в Oracle, щоб перевірити свою відповідь, я виявив, що Oracle відхилив DESC як назву стовпця.
Янек Богуцький

Вибачте, що я просто
скоротив

Відповіді:


412

Цей синтаксис недійсний в Oracle. Ви можете зробити це:

UPDATE table1 SET table1.value = (SELECT table2.CODE
                                  FROM table2 
                                  WHERE table1.value = table2.DESC)
WHERE table1.UPDATETYPE='blah'
AND EXISTS (SELECT table2.CODE
            FROM table2 
            WHERE table1.value = table2.DESC);

Або ви могли б бути в змозі зробити це:

UPDATE 
(SELECT table1.value as OLD, table2.CODE as NEW
 FROM table1
 INNER JOIN table2
 ON table1.value = table2.DESC
 WHERE table1.UPDATETYPE='blah'
) t
SET t.OLD = t.NEW

Це залежить, якщо Oracle вважає вбудований вигляд оновленим ( оновлення для другого оператора залежить від деяких правил, перерахованих тут ).


5
Я зробив другий приклад, але мусив додати псевдоніми до імен стовпців у select, а потім посилати їх своїми іменами в SET, але це спрацювало, спасибі
Густаво Рубіо

41
Другий приклад має перевагу, що ви можете протестувати SQL, перш ніж реально виконати оновлення.
Даніель Рейс

10
Другий приклад працював на мене. Мені це подобається, тому що він виглядає чистим і читабельним. Не знайте, які плюси і мінуси є між ними, коли справа доходить до продуктивності. Але я зараз про це не хвилювався, тому що я використовував це для одноразового сценарію для виправлення поганих даних.
немо

5
Другий працював на мене :). Oracle - одна сильна, але дивна тварина: /
elrado

10
Пояснення щодо збереженої у ключі вимоги до оновлених
Вадим,

202

Використовуй це:

MERGE
INTO    table1 trg
USING   (
        SELECT  t1.rowid AS rid, t2.code
        FROM    table1 t1
        JOIN    table2 t2
        ON      table1.value = table2.DESC
        WHERE   table1.UPDATETYPE='blah'
        ) src
ON      (trg.rowid = src.rid)
WHEN MATCHED THEN UPDATE
    SET trg.value = code;

2
Працює чудово, але Oracle вимагає від мене сказати merge into table 1 tі так далі.
Майкл-О

1
Пізно на вечірку, але це все-таки хороша нитка. Мені потрібно знати, тха ... чи я щось пропустив? Основна таблиця, "table1". У ВИКОРИСТАННІ таблиця1 псевдонім як t1. Таблиця2, псевдонімна як t2, але у ВКЛ посилання є ...? Зовнішня таблиця1 - не t1 - це посилання на зовнішню таблицю чи тип? Таблиця2? Не t2? Je suis заплутався. Шанувальник кращих псевдонімів ...
Марк

Ось лише тут, якщо ваш ключ (trg.rowid або src.rid) містить один дублюваний елемент, цей пункт викликає помилку: ora-30926.ora-code.com
Henrique

@Marc У ON, trg- псевдонім для головної таблиці table1("зовнішня" таблиця за вашою логікою) і srcпосилається на USINGгрупу ("внутрішня таблиця" за вашою логікою). Але так, напевно, можна було б послатись краще, але я зміг це дотримуватися.
vapcguy

1
@supernova: відповідь тоні - це оновлення вбудованого перегляду. Це може спрацювати в деяких випадках, але представлення повинно бути "збереженим ключем" (кожна об'єднана таблиця повинна бути об'єднана рівністю у своєму первинному ключі чи унікальному наборі поля). Це гарантує, що кожен запис у цільовій таблиці вносить щонайменше один запис у результуючому наборі рядків, а отже, кожен запис у цільовій таблиці оновлюється не більше одного разу.
Quassnoi

25

MERGEз WHEREпунктом:

MERGE into table1
USING table2
ON (table1.id = table2.id)
WHEN MATCHED THEN UPDATE SET table1.startdate = table2.start_date
WHERE table1.startdate > table2.start_date;

WHEREЦя стаття потрібна, оскільки стовпці, на які посилається цей ONпункт, не можуть бути оновлені.


Ця версія, напевно, чистіша, але вона не викликає зручності, тому що я не знаю, щоб уникнути запуску тригерів оновлення для незмінних рядків за допомогою цього синтаксису. (Я припускаю, що тригери потрібні для змінених рядків.)
sf_jeff


11

Не використовуйте деякі відповіді вище.

Деякі пропонують використовувати вкладені SELECT, не робіть цього, болісно повільно. Якщо у вас є багато записів для оновлення, використовуйте приєднатися, тому щось на зразок:

update (select bonus 
        from employee_bonus b 
        inner join employees e on b.employee_id = e.employee_id 
        where e.bonus_eligible = 'N') t
set t.bonus = 0;

Дивіться це посилання для отримання більш детальної інформації. http://geekswithblogs.net/WillSmith/archive/2008/06/18/oracle-update-with-join-again.aspx .

Також переконайтеся, що на всіх таблицях, до яких ви приєднуєтесь, є первинні ключі.


7

Як зазначено тут , загальним синтаксисом першого рішення, запропонованого Тоні Ендрюсом, є:

update some_table s
set   (s.col1, s.col2) = (select x.col1, x.col2
                          from   other_table x
                          where  x.key_value = s.key_value
                         )
where exists             (select 1
                          from   other_table x
                          where  x.key_value = s.key_value
                         )

Я думаю, що це цікаво, особливо якщо ви хочете оновити більше одного поля.


Це не працює для мене. Він оновлює всю таблицю.
Натасія Таварес

3

Цей наступний синтаксис працює для мене.

UPDATE
(SELECT A.utl_id,
    b.utl1_id
    FROM trb_pi_joint A
    JOIN trb_tpr B
    ON A.tp_id=B.tp_id Where A.pij_type=2 and a.utl_id is null
)
SET utl_id=utl1_id;

@JimGarrison Будь ласка, відредагуйте цю відповідь, щоб я міг видалити свій голос .... Я намагався використовувати цей синтаксис, і він не оновлював свою таблицю. Я з'ясував, чому - моє SETробив, REPLACEі я намагався зачистити певний рядок у стовпці - виявляється, що Oracle трактує ''як нуль, і це поле не могло бути скасовано нанівець. Я думав, що синтаксис - це лише оновлення темп-таблиці замість реальної, але я помилявся.
vapcguy

2

Використовуючи опис замість desc для table2,

update
  table1
set
  value = (select code from table2 where description = table1.value)
where
  exists (select 1 from table2 where description = table1.value)
  and
  table1.updatetype = 'blah'
;

чому ви хочете запустити два окремі запити на table2
Jitendra Vispute

2

Це прекрасно працює оракул

merge into table1 t1
using (select * from table2) t2
on (t1.empid = t2.empid)
when matched then update set t1.salary = t2.salary

Можна встановити кілька властивостей, додавши кому в кінці цього. Мені потрібно було зробити t1.First_Name = t2.FirstName, t1.Last_Name = t2.LastNameтаблицю після відповідності її в колонці "UserName" ( t1.UserName = t2.UserName), щоб отримати їх ім'я з таблиці під назвою UserInfo ( select * from UserInfo) t2). База даних була такою, коли вона використовувала UserName як основний ключ для UserInfo скрізь, замість того, щоб розміщувати FirstName та LastName безпосередньо в таблиці. Це виправили це!
vapcguy

Ця відповідь нічого не додає до відповіді, яку вже дав Квасной за п’ять років до вашого.
Корм

0
UPDATE table1 t1
SET t1.value = 
    (select t2.CODE from table2 t2 
     where t1.value = t2.DESC) 
WHERE t1.UPDATETYPE='blah';

0
UPDATE IP_ADMISSION_REQUEST ip1
SET IP1.WRIST_BAND_PRINT_STATUS=0
WHERE IP1.IP_ADM_REQ_ID        =
  (SELECT IP.IP_ADM_REQ_ID
  FROM IP_ADMISSION_REQUEST ip
  INNER JOIN VISIT v
  ON ip.ip_visit_id=v.visit_id
  AND v.pat_id     =3702
  ); `enter code here`

0

Що стосується повноти, і тому, що ми говоримо про Oracle, це може зробити це також:

declare
begin
  for sel in (
    select table2.code, table2.desc
    from table1
    join table2 on table1.value = table2.desc
    where table1.updatetype = 'blah'
  ) loop
    update table1 
    set table1.value = sel.code
    where table1.updatetype = 'blah' and table1.value = sel.desc;    
  end loop;
end;
/

1
Це могло б зробити це, але мова йде про найповільніший спосіб.
APC

-1
UPDATE (SELECT T.FIELD A, S.FIELD B
FROM TABLE_T T INNER JOIN TABLE_S S
ON T.ID = S.ID)
SET B = A;

A і B - поля псевдоніму, вам не потрібно вказувати таблицю.


1
Привіт, Ден. Ви розміщуєте досить старе питання, на яке вже є дуже хороші відповіді. Чи можете ви пояснити, коли питання є кращим перед іншими рішеннями?
Ноель Відмер

1
Звичайно, я бачив відповідь, де написано b = a, вказуючи ім'я таблиці (table1.B = table2.A), але немає потреби вказувати на таблицю.
Ден Андерсон

Ви фактично оновлюєте поля з подання, які відображаються в таблиці. Якби внутрішній вигляд був псевдонімом h, тоді версією "самодокументування" було б "встановити hb = ha".
sf_jeff

-4
update table1  a 
   set a.col1='Y' 
 where exists(select 1 
                from table2 b
               where a.col1=b.col1 
                 and a.col2=b.col2
             )
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.