Оновіть оператор з внутрішнім приєднанням в 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.