【问题标题】:Using BULK COLLECT with rownum将 BULK COLLECT 与 rownum 一起使用
【发布时间】:2018-06-26 06:56:36
【问题描述】:

下面的查询会批量选择,然后循环更新记录。我想在这里使用 BULK COLLECT INTO 和 FORALL 构造来提高性能。但是查询使用 rownum 来更新循环中的列。无论如何我可以在获取 rownum 的同时使用 BULK COLLECT INTO 吗?

     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;

谢谢

【问题讨论】:

  • 您绝对不应该使用 rownum 进行更新 :) 使用您的主键或其他唯一键
  • 感谢 Sudipta 的回复。在 SQL 选择查询中,我将结果按某种顺序排列,我需要在其中一个列中更新该顺序。我认为我不能从主要实现相同的事情或其他键。 :)
  • 如果你想要一个订单,使用排名功能。我建议您重新考虑使用rownum。你应该在 ASK TOM 或其他 Stackoverflow 问题上阅读它
  • 是的,您可以使用rownum 或您想要的任何其他内容。什么不工作?
  • 您已就康纳的回答向我发表了评论。只是为了回答您的问题,是的,即使我们订购表记录/行,ROWID 也会相同。 rowid 唯一标识每一行的地址,并且不是在运行时生成的,如ROWNUM。 google rowid 让 Oracle 了解更多。

标签: sql oracle rownum forall bulk-collect


【解决方案1】:

您不需要批量收集,您的 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;

【讨论】:

  • 谢谢Kaushik,我已经测试了你的查询。速度更快,结果与原始查询一致。
【解决方案2】:

您可以将 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;
/

【讨论】:

  • @Kaushik Nayak,感谢您的回复。只是为了了解您的“开启”标准,即使我们订购表记录/行,rowid 也会相同?我只想检查您的查询是否会更新预期的相同行。谢谢。
  • 感谢康纳的回复。我会检查一下。
  • 再次感谢康纳。我接受你的回答,尽管我将使用 Merge Into,因为这里的行数会非常少,大约 250 〜所以我认为所有执行时间几乎相同。跨度>
猜你喜欢
  • 1970-01-01
  • 2021-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-28
  • 1970-01-01
相关资源
最近更新 更多