Использование BULK COLLECT с rownum

Ниже запрос выполняет массовый выбор, а затем обновляет записи в цикле. Я хочу использовать здесь конструкции BULK COLLECT INTO и FORALL для повышения производительности, но запрос использует rownum для обновления столбца в цикле. Могу ли я использовать BULK COLLECT INTO во время получения rownum?

     FOR rec IN
        (SELECT rownum rn,
            b.*
        FROM
            (SELECT *
            FROM temp_final a
           WHERE reid  = 1
            AND retype  = 9
            AND sid         = 'r123'
            AND pid = 2191
            ORDER BY a.horder DESC nulls last,
                sname                         ,
                rowgroup                           ,
                dpct DESC nulls last       ,
                name
            ) b
        )
        LOOP
            UPDATE temp_final
            SET horder=rec.rn
             WHERE reid  = 1
            AND retype  = 9
            AND sid         = 'r123'
            AND pid = 2191
            AND mid   =rec.mid;
        END LOOP;

Спасибо


person Khushi    schedule 26.06.2018    source источник
comment
точно не стоит использовать rownum для обновлений :) Используйте свой первичный или другой уникальный ключ   -  person Sudipta Mondal    schedule 26.06.2018
comment
Спасибо Sudipta за ваш ответ. В запросе выбора SQL я получаю результат в определенном порядке, который мне нужно обновить в одном из столбцов. Я не думаю, что я могу добиться того же с помощью первичных или других ключей. :)   -  person Khushi    schedule 26.06.2018
comment
Если вам нужен порядок, используйте функцию ранжирования. Я предлагаю вам пересмотреть использование rownum. вы должны прочитать об этом в ASK TOM или другом вопросе Stackoverflow   -  person Sudipta Mondal    schedule 26.06.2018
comment
Да, вы можете использовать rownum или что угодно еще. Что не работает?   -  person William Robertson    schedule 26.06.2018
comment
Вы написали мне адресованный мне комментарий по поводу ответа Коннора. Чтобы ответить на ваш вопрос, да, ROWID будет таким же, даже если мы упорядочим записи / строки таблицы. Rowid однозначно определяет адрес каждой строки и не генерируется во время выполнения, как ROWNUM. Google rowid для Oracle, чтобы понять больше.   -  person Kaushik Nayak    schedule 26.06.2018


Ответы (2)


Вам не нужен массовый сбор, то, что пытается сделать ваше обновление pl / sql, можно переписать как один оператор MERGE INTO, что было бы намного эффективнее, чем использование FORALL. Если вы по-прежнему настаиваете на использовании forall, вы можете преобразовать это MERGE в блок forall.

MERGE INTO temp_final tgt USING (
    SELECT rowid,
        ROW_NUMBER() OVER(
            ORDER BY
                horder DESC NULLS LAST,sname,rowgroup,dpct DESC NULLS LAST,name
        ) rn
    FROM
        temp_final
    WHERE
        reid = 1
        AND retype = 9
        AND sid = 'r123'
        AND pid = 2191
)
src ON ( tgt.rowid = src.rowid )
WHEN MATCHED THEN UPDATE SET tgt.horder = src.rn;
person Kaushik Nayak    schedule 26.06.2018
comment
Спасибо, Каушик, я проверил ваш запрос. Он быстрее и результаты соответствуют исходному запросу. - person Khushi; 02.07.2018

Вы можете захватить rowid вместе с начальным выбором, сбросить партию в массивы, а затем использовать это в своем FORALL, например

declare
  l_num_list sys.odcinumberlist := sys.odcinumberlist();
  l_char_list sys.odcivarchar2list := sys.odcivarchar2list();
begin  
SELECT rownum rn,rowidtochar(rid)
bulk collect into l_num_list, l_char_list
FROM
            (SELECT a.*, rowid rid
            FROM temp_final a
           WHERE reid  = 1
            AND retype  = 9
            AND sid         = 'r123'
            AND pid = 2191
            ORDER BY a.horder DESC nulls last,
                sname                         ,
                rowgroup                           ,
                dpct DESC nulls last       ,
                name
            ) b;

forall i in 1 .. l_num_list.count
            UPDATE temp_final
            SET horder=l_num_list(i)
            WHERE rowid = chartorowid(l_char_list(i));

end;
/
person Connor McDonald    schedule 26.06.2018
comment
@Kaushik Nayak, спасибо за ответ. Просто чтобы понять ваши критерии включения, rowid будет таким же, даже если мы упорядочим записи / строки таблицы? Я просто хочу проверить, обновит ли ваш запрос те же строки, которые предназначены. Спасибо. - person Khushi; 26.06.2018
comment
Спасибо Коннору за ваш ответ. Я проверю это. - person Khushi; 26.06.2018
comment
Еще раз спасибо, Коннор. Я принимаю ваш ответ, хотя я буду использовать Merge Into, так как количество строк здесь будет очень меньше, около 250 ~, поэтому я думаю, что время выполнения будет почти таким же. - person Khushi; 02.07.2018