Используя явный курсор и цикл, не могу найти ошибку - PullRequest
0 голосов
/ 28 сентября 2019

Я пытаюсь выяснить код для добавления нового столбца в таблицу 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;
    /

enter image description here

Ответы [ 2 ]

1 голос
/ 28 сентября 2019

Решение может быть таким:

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);
1 голос
/ 28 сентября 2019

Подумайте, как бы вы сделали это сами.У вас есть список кодов стилей и идентификаторов артиста.Вам нужно пройти по списку и посчитать, сколько раз появляется один и тот же идентификатор артиста.Вы должны сделать это для каждого отдельного идентификатора артиста в списке.Это означало бы просмотреть список несколько раз.Что если бы вы могли отсортировать список по идентификатору артиста?Тогда вам нужно будет пройти список всего один раз, потому что все строки с одинаковым идентификатором конферансье появляются вместе.Следовательно, ваш курсор должен быть ...

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

Итак, вы начинаете проходить по строкам в вашем списке.Пока идентификатор артиста текущей строки совпадает с идентификатором предыдущей строки, вы увеличиваете количество.Когда появляется новый идентификатор артиста, вы начинаете новый счет, верно?Кроме того, при изменении идентификатора артиста у вас будет количество стилей для последнего идентификатора артиста.Если это число больше одного (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;
...