2017-02-02 3 views
0

Я пытаюсь обновить таблицу с помощью своего рода сложного исходного набора данных. Существует таблица, в которой содержится информация о продуктах. он также содержит описание полевого продукта. Это поле иногда по-прежнему имеет некоторые старые описания и нуждается в обновлении в базе данных.Обновление со сложными объединениями

, но объединенная таблица также должна быть отфильтрована на языке, который выполняется другим подзапросом или соединением.

SELECT products.DESCSH as old_desc 
     ,parcel.DESCSH as new_desc 
    FROM parcel 
     ,products 
    WHERE parcel.PRODU_INTERNUM = products.INTERNUM 
    AND parcel.NUM LIKE '2%REGEN' 
    and (SELECT COMPA.LANG FROM COMPA WHERE COMPA.NUM = parcel.COMPA_NUM) = products.LANG 
    and trim(upper(products.DESCSH)) <> trim(upper(parcel.DESCSH)) 

это базовый выбор. (задача в основном заключается в обновлении new_desc с помощью old_desc)

Теперь, когда я понятия не имел, как это сделать, я увидел здесь 3 метода. MERGE подход

merge into gc_prcel target 
    using (
     Select p.descsh 
       ,p.internum 
      from p 
       ,par 
      where sysdate between p.vldty_beg and p.vldty_end 
      and p.internum = par.produ_internum 
      and p.lang = (SELECT COMPA.LANG FROM COMPA WHERE COMPA.NUM = par.COMPA_NUM) 
     ) source 
    on (target.produ_internum = source.internum) 
    when matched then update 
    set target.descsh = source.descsh 
    where target.num like '2%REGENSDO' 
    and trim(upper(target.descsh)) <> trim(upper(target.descsh)); 

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

Метод с пунктом EXIST (я мог бы использовать это, но я найти другие подходы, более элегантный) и один, где вы непосредственно обновить поле из подвыборки так:

update 
    (SELECT products.DESCSH as old_desc 
      ,parcel.DESCSH as new_desc 
     FROM parcel 
      ,products 
     WHERE parcel.PRODU_INTERNUM = products.INTERNUM 
     AND parcel.NUM LIKE '2%REGENSDO' 
     and (SELECT COMPA.LANG FROM COMPA WHERE COMPA.NUM = parcel.COMPA_NUM) = products.LANG 
     and trim(upper(products.DESCSH)) <> trim(upper(parcel.DESCSH))) descriptions 
    set descriptions.new_desc = descriptions.old_desc; 

это один кидает (ORA-01779: невозможно изменить столбец, который сопоставляется с таблицей, не сохраненной ключом)

Является ли задача, которую я пытаюсь сделать даже с помощью оператора слияния, или мне нужно использовать обновление, существует и почему мой первый подход не работает с ORA-01779)

ответ

0

Вы делаете умную вещь - как в MERGE, так и в UPDATE - это обновление строки только тогда, когда значение изменяется. Но в MERGE вы написали это - можете ли вы заметить ошибку? (Который, возможно, является причиной или одной из причин, в течение длительного времени выполнения.)

and trim(upper(target.descsh)) <> trim(upper(target.descsh)); 

ОК, это не должно быть игрой в догадки; один из аргументов должен быть source.deschs, у вас есть target с обеих сторон.

Редактировать: Или на самом деле ждать, это должно заставить утверждение ничего не обновлять, поскольку это условие никогда не ИСТИНА. Это ТОЧНО утверждение, которое вы использовали? Конец Редактировать

Для ОБНОВЛЕНИЯ и полученной ошибки я написал эту короткую статью в домене «Документация» переполнения стека. Он объясняет полученную вами ошибку и как ее исправить: Update with joins

+0

Hi. Большое спасибо за ваш быстрый ответ ... На самом деле это БЫЛО заявление, которое я использовал последним. но мне пришлось отменить его, потому что он не прекратил выполнение –

+0

@JanZimmermann - это действительно странно.Вы сказали, что в некоторых прогонах это утверждение обновляло многие строки, но предложение 'where' никогда не является ИСТИННЫМ (это никогда не бывает так, что что-то отличается от самого себя). Так как это возможно? – mathguy

+0

Да, я знаю, что вы имеете в виду :), но я также сказал, что я пробовал много разных вариантов этого утверждения, и если бы он не выдавал ошибку или не выполнялся неопределенно долго, он обновлял бы 80 тыс. Записей вместо 400. К сожалению, эти шаги между больше не доступны для меня. Btw я уже должен был выполнить задачу, поэтому я использовал метод с существующим .. но мне все еще интересно, как я мог выполнить эту задачу с помощью оператора Merge –

0

Если gc_prcel и par (я полагаю, что это действительно таблица посылок, которую вы упомянули в операторах обновления?), Это разные таблицы, тогда я бы сделал слияние, что-то вроде:

merge into gc_prcel target 
    using (
     Select p.descsh 
       ,p.internum 
      from p 
       inner join par on p.internum = par.produ_internum 
            and trim(upper(p.descsh)) <> trim(upper(par.descsh) 
      where sysdate between p.vldty_beg and p.vldty_end 
      and p.lang = (SELECT COMPA.LANG FROM COMPA WHERE COMPA.NUM = par.COMPA_NUM) 
      and par.num like '2%REGENSDO'); 
     ) source 
    on (target.produ_internum = source.internum) 
    when matched then update 
    set target.descsh = source.descsh; 

Если, однако, это таблица посылок вы пытаетесь обновить, я бы что-то вроде:

merge into parcel tgt 
    using (select p.internum, 
       p.descsh, 
       compa.num 
     from products p 
       inner join compa on p.lang = compa.lang 
     where sysdate between p.vldty_beg and p.vldty_end) src 
    on (tgt.produ_internum = src.internum 
     and tgt.num like '2%REGENSDO' 
     and tgt.compa_num = src.compa_num) 
when matched then 
    update set tgt.descsh = src.descsh 
    where  trim(upper(tgt.descsh)) != trim(upper(src.descsh)); 
+0

спасибо за быстрый ответ (я не знал, что вы, ребята, :)) У меня нет времени прямо сейчас, чтобы проверить это, но сделаю это первым делом завтра утром. И да, gc_prcel и посылка одинаковы (я думал, что я был осторожен, чтобы не публиковать фактические имена объектов: /) –

+0

В подзадаче вы ссылаетесь на par.compa_num, но нет ни одного псевдонима. Я думаю, что мне нужно также присоединиться к таблице пакетов в подзапросе, потому что compa_num доступен только там, и мне нужно это поле для определения языков (LANG) –

+0

Хорошая точка. Подумайте об этом, спасибо! – Boneist

Смежные вопросы