1

我是编码新手,我正在尝试使用游标和循环更新下表(而不依赖于任何行号函数)。我的表是以 id 和 model 作为列的 Cars。问题是我正在尝试更新具有重复数字的 id 列,例如表看起来像这样。我想让 ID 成为主键。

ID    MODEL 
1    Civic 
1    Accord 
3    Buick 
3    Corolla 
3    Prius 
3    Saab 

我在下面尝试过,但它只是更改了所有值。我究竟做错了什么?这个循环在做什么?

DECLARE 
    ids number; 
    models varchar2 (50); 
    previous_id number := 0; 
    new_id number :=0; 
    cursor getRow is select * from CARS; 

BEGIN  
    open getRow; 
    fetch getRow into ids, models; 
    previous_id := ids; 
    loop 
        fetch getRow into ids, models; 
        if getRow%found 
        then  
            new id := previous_id +1; 
            if ids = previous_id 
            then  
                  update CARS 
                set ID = new_id 
                where ID = previous_id; 
            else  
                previous_id := ids;     
            end if; 
            else 
                exit; 
        end if; 
    end loop; 
    close getRow; 
END;
4

1 回答 1

2

这是实现目标的最简单方法:

update cars
set id = rownum;

这会将 ID 设置为唯一的、单调递增的数字。

您说您是编码新手,所以也许这就是您不想使用简单答案的唯一原因?

无论如何,您的代码无法正常工作的原因是您选择了一组 ID,然后批量更新它们。我认为您假设您的更新只是影响当前行,但它不会:它使用共享 ID 更新所有行。此外,您关于 NEW_ID 和 PREVIOUS_ID 的逻辑很奇怪:您需要仅使用一个变量来保持连续性。

如果您坚持使用循环,则需要使用 FOR UPDATE 游标并使用 WHERE CURRENT OF 仅更新当前行:

DECLARE 
    ids number; 
    models varchar2 (50); 
    previous_id number :=0; 
    cursor getRow is 
       select * from CARS
       for update of id; 

BEGIN  
    open getRow; 
    fetch getRow into ids, models; 
    loop 
        if getRow%found 
        then  
            if ids = previous_id 
            then  
                previous_id := previous_id +1; 
                update CARS 
                set ID = new_id 
                where current of getRow; 
            else  
                previous_id := ids;     
            end if; 
        else 
            exit; 
        end if; 
        fetch getRow into ids, models; 
    end loop; 
    close getRow; 
END;

但这与纯 SQL 解决方案相比,代码太多了。它的执行速度也会慢得多。如果这是一个自学 PL/SQL 的玩具练习,那么这些都不重要,但它不是在实际应用程序中编码的那种东西。

于 2012-10-14T14:03:27.103 回答