任何人都可以帮助我使用我的pl / sql脚本来更新/合并数据库

时间:2012-02-02 17:04:49

标签: sql oracle cursor

我制作了一个游标,以便合并/更新数据库中的记录

我想知道它是否正确或是否有任何建议以改进查询。

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;

3 个答案:

答案 0 :(得分:7)

假设代码在功能上符合您的要求......

1)删除异常处理程序。捕获一个你无法处理的未知异常没有任何好处,除非你正在做一些事情,比如记录它并重新抛出它。仅捕获异常以调用dbms_output不仅隐藏了调试异常所需的异常详细信息和堆栈跟踪,如果调用方不能从缓冲区中读取{{1},它可能会完全隐藏异常写入。

2)在循环中提交通常是一个坏主意。最重要的是,如果你的会话在中间死亡会发生什么?您有一个部分提交的更新,以后在以后重新启动代码时无法恢复操作。您必须重新更新之前更新的所有行以及您提交的可能具有下游影响的更新。并且在循环中提交会减慢代码的速度。

3)如果您要做的只是更新表,最有效的方法是编写一个dbms_output语句,一次更新所有行,而不是迭代光标并做很多事情单行更新。可能有其他理由支持游标(例如,它可能使代码更容易让其他开发人员理解),但从性能的角度来看,如果你能在SQL中做到这一点,那么SQL将是最有效的方法。 / p>

答案 1 :(得分:4)

1)您正在用无意义的错误替换有意义的错误。另外,如果您还没有set output on,则会完全错过错误。最好的办法是简单地删除异常块。如果您不能这样做,则应至少将SQLERRMDBMS_UTILITY.FORMAT_ERROR_BACKTRACE转储到DBMS_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;

答案 2 :(得分:0)

我建议你使用现代连接语法

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