使用显式游标和循环,找不到错误

Posted

技术标签:

【中文标题】使用显式游标和循环,找不到错误【英文标题】:Using explicit cursor and loop, can't find error 【发布时间】:2019-09-28 04:04:55 【问题描述】:

我正在尝试找出代码来向 ATA_ENTERTAINER 表中添加一个名为 MORE_THAN_ONE 的新列,其数据类型为 NUMBER(此代码将在 PL/SQL 代码之外)。如果艺人有多个样式类型,则此列将保存其拥有的样式类型的数量(如果有,则在此列中放置 NULL)。

我的代码应该使用明确的光标和循环结构,遍历每个艺人并确定他们拥有的样式数量。如果一个艺人有多个,我需要修改该艺人的 MORE_THAN_ONE 列中的值以及样式数(如果不超过一个,则应在此列中输入 NULL)。我还需要使用 FOR UPDATE 和 WHERE CURRENT OF 作为我的解决方案的一部分。使用基本循环来解决这个问题, 以及任何决策结构的 IF。

这就是我现在所拥有的。 它没有显示任何错误,但不知何故,当我运行此代码时,我的表没有更新/更改。

DECLARE
    ata_entId ata_entertainer.entertainer_id%TYPE; 
    ata_st_entId ata_entertainers_style.entertainer_id%TYPE; 
    ata_more ata_entertainer.more_than_one%TYPE;
    ata_count NUMBER(10) := 0; 

    CURSOR ata_rec IS 
        SELECT  entertainer_id
        FROM ata_entertainers_style
        WHERE ata_st_entId = ata_entId
        FOR UPDATE;
BEGIN 
    OPEN ata_rec; 
    LOOP 
    FETCH  ata_rec INTO ata_st_entId; 
    EXIT WHEN ata_rec%NOTFOUND; 
    IF ata_st_entId = ata_entId THEN ata_more := ata_count+1; 
    UPDATE ata_entertainer SET more_than_one = ata_more
    WHERE CURRENT of ata_rec;
    END IF;
    END LOOP;
    CLOSE ata_rec; 
    END;
    /

【问题讨论】:

请贴出数据库表结构ATA_ENTERTAINER @Abra 我刚刚做了! 根据您发布的图表,表ATA_ENTERTAINER 不包含MORE_THAN_ONE 列。如您的问题所述,您是否已将该列成功添加到表格中? 这是学校的练习吗?在“现实”生活中,人们会使用一条更新语句来执行任务。 【参考方案1】:

解决方案可能是这样的:

DECLARE
    ata_more ata_entertainer.more_than_one%TYPE;

    CURSOR ata_rec IS 
        SELECT entertainer_id
        FROM ata_entertainer
        FOR UPDATE;
BEGIN 

   for aEntertainer in ata_rec LOOP
      select count(*)
      into ata_more
      from ATA_ENTERTAINERS_STYLE
      WHERE entertainer_id = aEntertainer.entertainer_id;
      IF ata_more > 1 then
          UPDATE ata_entertainer SET more_than_one = ata_more
          WHERE CURRENT of ata_rec;
      END IF;
   END LOOP;
END;

实际上,我不知道 WHERE CURRENT OF 是否在 FOR ... IN LOOP 中工作 - 我把这个留给你去发现。

在现实生活中,您将使用一条语句运行此更新:

update ata_entertainer a SET more_than_one = 
   (select NULLIF(count(*), 1) 
    FROM ATA_ENTERTAINERS_STYLE b 
    where a.entertainer_id = b.entertainer_id);

【讨论】:

【参考方案2】:

想想你自己会怎么做。你有一个风格代码和艺人 ID 的列表。您需要浏览列表并计算同一个艺人 ID 出现的次数。您必须为列表中的每个不同的艺人 ID 执行此操作。这意味着要多次浏览列表。如果您可以按艺人 ID 对列表进行排序怎么办?然后您只需要浏览该列表一次,因为具有相同艺人 ID 的所有行会一起出现。因此,您的光标应该是...

cursor ATA_REC is
  select ENTERTAINER_ID
    from ATA_ENTERTAINERS_STYLE
   order by ENTERTAINER_ID
for update;

因此,您开始浏览列表中的行。只要当前行的艺人 ID 与上一行的艺人 ID 相同,就可以增加计数。当一个新的艺人 ID 出现时,你开始一个新的计数,对吧?此外,当艺人 ID 更改时,您将获得最后一个艺人 ID 的样式数。如果该计数超过一 (1),您需要更新 ATA_ENTERTAINER 表。

这是我的解决方案。请注意,它可以编译(在 Oracle 11g Express Edition 中),但我没有在样本数据上对其进行测试(太懒了:-)

declare
  ATA_ENT_ID        ATA_ENTERTAINER.ENTERTAINER_ID%type;
  L_ENTERTAINER_ID  ATA_ENTERTAINER.ENTERTAINER_ID%type;
  L_FIRST           boolean;
  L_SUM             number(3); -- Assume less than one thousand styles for single entertainer.
--
  cursor ATA_REC is
    select ENTERTAINER_ID
      from ATA_ENTERTAINERS_STYLE
     order by ENTERTAINER_ID
    for update;
begin
  L_ENTERTAINER_ID := -1;
  L_FIRST := true;
  L_SUM := 0;
  open ATA_REC;
  loop
    fetch ATA_REC into ATA_ENT_ID;
    exit when ATA_REC%notfound;
    if ATA_ENT_ID = L_ENTERTAINER_ID then
      L_SUM := L_SUM + 1;
    else
      if L_FIRST then
        L_FIRST := false;
        L_SUM := 1;
        L_ENTERTAINER_ID := ATA_ENT_ID;
      else
        if L_SUM > 1 then
          update ATA_ENTERTAINER
             set MORE_THAN_ONE = L_SUM
           where current of ATA_REC;
        end if;
      end if;
      L_SUM := 0;
      L_ENTERTAINER_ID := ATA_ENT_ID;
    end if;
  end loop;
--
  -- Make sure we update the last entertainer.
  if L_SUM > 1 then
    update ATA_ENTERTAINER
       set MORE_THAN_ONE = L_SUM
     where current of ATA_REC;
  end if;
end;

【讨论】:

以上是关于使用显式游标和循环,找不到错误的主要内容,如果未能解决你的问题,请参考以下文章

在表中找不到给定记录时如何处理游标中的异常

找不到名为游标的模块

在我的 for 循环中找不到逻辑错误

selenium 找不到元素 (显式等待 和隐式等待的区别)

找不到接受提供的参数的“logInWithPermissions”的重载

在 PL/SQL 脚本上使用 DB 链接会引发“找不到表”错误