为了合并/更新数据库中的记录,我做了一个游标
我想知道它是否正确,或者是否有人有任何建议,以改善查询。
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条答案
按热度按时间7xzttuei1#
假设代码在功能上实现了您想要的功能……
1)删除异常处理程序。捕获一个你无法处理的未知异常没有任何好处,除非你做一些类似记录它并重新抛出它的事情。捕获一个异常只是为了调用
dbms_output
,这不仅隐藏了异常细节和调试异常所需的堆栈跟踪,而且如果调用者碰巧没有从dbms_output
写入的缓冲区读取数据,它可能会完全隐藏异常。2)在循环中提交通常是一个坏主意。最重要的是,如果您的会话在中途中断会发生什么?您将有一个部分提交的更新,当您稍后重新启动代码时,无法恢复操作。您必须重新更新之前更新过的所有行,并且提交了可能会对下游产生影响的更新。在循环中提交会真实的地减慢代码的速度。
3)如果您要做的只是更新一个表,那么最有效的方法是编写一个
UPDATE
语句来一次性更新所有行,而不是迭代游标并执行大量的单行更新。可能还有其他原因支持游标(例如,它可能使其他开发人员更容易理解代码),但从性能的Angular 来看,如果可以在SQL中实现,SQL将是最有效的方法。h9a6wy2h2#
1)你用一个无意义的错误替换了一个有意义的错误。另外,如果你没有
set output on
,一个错误将被完全忽略。最好的办法是简单地删除异常块。如果不能这样做,则应该至少转储SQLERRM
,可能还要转储DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
到DBMS_OUTPUT
。为了很好地捕获和记录错误,您需要将异常细节传递给一个单独的过程,该过程将使用自治事务将这些细节写入表。不过,即使在这种情况下,您最好在记录错误之后重新引发它。2)在大多数情况下,提交每X条记录是一种糟糕的做法。如果这些记录一起被更新,那么它们应该是同一事务的一部分。
3)您可以使用
UPDATE
或MERGE
在单个语句中完成此操作。通常这是首选的,因为它避免了额外的上下文切换。就个人而言,我喜欢MERGE
在这个场景中:c3frrgcw3#
我建议您使用现代的连接语法