oracle 谁能帮我用我的pl/sql脚本在数据库中更新/合并

brqmpdu1  于 2023-05-16  发布在  Oracle
关注(0)|答案(3)|浏览(117)

为了合并/更新数据库中的记录,我做了一个游标
我想知道它是否正确,或者是否有人有任何建议,以改善查询。

DECLARE
CURSOR c_itemloc
IS
SELECT 
    item ,
    loc ,
    loc_type ,
    source_method ,
    primary_supp ,
    source_wh
FROM
  (SELECT dc_vert.item ,
    dc_vert.loc ,
    dc_vert.loc_type ,
    dc_vert.source_method ,
    dc_vert.primary_supp ,
    w.primary_vwh source_wh --,dc_vert.source_wh
    ,
    dc_vert.actie ,
    MAX(dc_vert.actie) over (PARTITION BY dc_vert.item, dc_vert.loc) actie_max ,
    COUNT(dc_vert.primary_supp) over (PARTITION BY dc_vert.item, dc_vert.loc) primary_count
  FROM dc_item_loc_pim_lms dc_vert ,
    item_supplier isu ,
    store sto ,
    wh w
  WHERE dc_vert.primary_supp    IS NOT NULL
  AND isu.item                   = dc_vert.item
  AND dc_vert.primary_supp       = isu.supplier
  AND W.WH                       = dc_vert.source_wh
  AND sto.store                  = dc_vert.loc
  AND ISU.SUPP_DISCONTINUE_DATE >= SYSDATE
  )
  WHERE actie       = actie_max
  AND primary_count = 1;
  l_item item_loc.item%TYPE;
  l_loc item_loc.loc%TYPE;
  loc_type item_loc.loc_type%TYPE;
  l_source_method item_loc.source_method%TYPE;
  l_primary_supp item_loc.primary_supp%TYPE;
  l_source_wh item_loc.source_wh%TYPE;

  i        NUMBER;
  l_commit VARCHAR2(1) := 'Y';
  BEGIN
  i             :=0;
  FOR r_itemloc IN c_itemloc
  LOOP
  i := i+1;
  UPDATE item_loc il
  SET 
    il.source_method        = r_itemloc.source_method ,     -- 'S'
    il.loc_type             = r_itemloc.loc_type ,      -- 'S'
    il.primary_supp         = r_itemloc.primary_supp ,
    il.source_wh            = r_itemloc.source_wh ,
    il.last_update_datetime = SYSDATE
  WHERE item                    = r_itemloc.item
  AND   loc                   = r_itemloc.loc;
  IF l_commit                   = 'Y' AND mod(i, 1000) = 0 THEN
  COMMIT ;
  END IF;
  END LOOP;
  EXCEPTION
  WHEN OTHERS THEN
     dbms_output.put_line('SOMETHING WENT WRONG');
  END;
7xzttuei

7xzttuei1#

假设代码在功能上实现了您想要的功能……
1)删除异常处理程序。捕获一个你无法处理的未知异常没有任何好处,除非你做一些类似记录它并重新抛出它的事情。捕获一个异常只是为了调用dbms_output,这不仅隐藏了异常细节和调试异常所需的堆栈跟踪,而且如果调用者碰巧没有从dbms_output写入的缓冲区读取数据,它可能会完全隐藏异常。
2)在循环中提交通常是一个坏主意。最重要的是,如果您的会话在中途中断会发生什么?您将有一个部分提交的更新,当您稍后重新启动代码时,无法恢复操作。您必须重新更新之前更新过的所有行,并且提交了可能会对下游产生影响的更新。在循环中提交会真实的地减慢代码的速度。
3)如果您要做的只是更新一个表,那么最有效的方法是编写一个UPDATE语句来一次性更新所有行,而不是迭代游标并执行大量的单行更新。可能还有其他原因支持游标(例如,它可能使其他开发人员更容易理解代码),但从性能的Angular 来看,如果可以在SQL中实现,SQL将是最有效的方法。

h9a6wy2h

h9a6wy2h2#

1)你用一个无意义的错误替换了一个有意义的错误。另外,如果你没有set output on,一个错误将被完全忽略。最好的办法是简单地删除异常块。如果不能这样做,则应该至少转储SQLERRM,可能还要转储DBMS_UTILITY.FORMAT_ERROR_BACKTRACEDBMS_OUTPUT。为了很好地捕获和记录错误,您需要将异常细节传递给一个单独的过程,该过程将使用自治事务将这些细节写入表。不过,即使在这种情况下,您最好在记录错误之后重新引发它。
2)在大多数情况下,提交每X条记录是一种糟糕的做法。如果这些记录一起被更新,那么它们应该是同一事务的一部分。
3)您可以使用UPDATEMERGE在单个语句中完成此操作。通常这是首选的,因为它避免了额外的上下文切换。就个人而言,我喜欢MERGE在这个场景中:

MERGE INTO item_loc il
USING      (SELECT item,
                   loc,
                   loc_type,
                   source_method,
                   primary_supp,
                   source_wh
            FROM   (SELECT dc_vert.item,
                           dc_vert.loc,
                           dc_vert.loc_type,
                           dc_vert.source_method,
                           dc_vert.primary_supp,
                           w.primary_vwh source_wh,
                           dc_vert.actie,
                           MAX(dc_vert.actie) OVER (PARTITION BY dc_vert.item, dc_vert.loc) actie_max,
                           COUNT(dc_vert.primary_supp) OVER (PARTITION BY dc_vert.item, dc_vert.loc) primary_count
                    FROM   dc_item_loc_pim_lms dc_vert,
                           item_supplier isu,
                           store sto,
                           wh w
                    WHERE  dc_vert.primary_supp IS NOT NULL
                       AND isu.item = dc_vert.item
                       AND dc_vert.primary_supp = isu.supplier
                       AND w.wh = dc_vert.source_wh
                       AND sto.store = dc_vert.loc
                       AND isu.supp_discontinue_date >= SYSDATE)
            WHERE  actie = actie_max AND primary_count = 1) itemloc
ON         (il.item = itemloc.item AND il.loc = itemloc.loc)
WHEN MATCHED THEN
   UPDATE SET
      il.source_method          = itemloc.source_method,
      il.loc_type               = itemloc.loc_type,
      il.primary_supp           = itemloc.primary_supp,
      il.source_wh              = itemloc.source_wh,
      il.last_update_datetime   = SYSDATE;
c3frrgcw

c3frrgcw3#

我建议您使用现代的连接语法

FROM
    dc_item_loc_pim_lms dc_vert
    INNER JOIN item_supplier isu
       ON dc_vert.item = isu.item AND
          dc_vert.primary_supp = isu.supplier
    INNER JOIN store sto
       ON dc_vert.loc = sto.store
    INNER JOIN wh w
       ON dc_vert.source_wh = w.wh
WHERE
    dc_vert.primary_supp IS NOT NULL AND
    isu.supp_discontinue_date >= SYSDATE

相关问题