PLSQL Вставить в цикл For

#oracle #plsql

Вопрос:

Я получил скрипт PL/SQL для вставки данных из другой таблицы, но результат оказался не таким, как я ожидал. Вставка в таблицу BBB сохраняет только первую строку циклов d_rec. Когда я попытался распечатать/вывести d-Rec в другом sql, он выдал мне все строки, сохраненные в таблице yyy.

я уже пробовал использовать курсор, но результат все тот же.

 DECLARE
GROUP_SEQ NUMBER;
TRANS_SEQ NUMBER;
ID NUMBER;
PP NUMBER := 1;
TRANS_ID NUMBER;
TRANS_SUM NUMBER;
UNIT VARCHAR(6);
DEBET NUMBER;
CREDIT NUMBER;

BEGIN
FOR v_rec in (SELECT unit from xxx)
LOOP
   FOR d_rec in (SELECT ID, TRANS_SUM, UNIT from yyy where unit = v_rec.unit )
   LOOP

     UPDATE YYY_SEQUENCE 
       SET SEQ_COUNT = SEQ_COUNT   1
       WHERE SEQ_NAME = 'GROUP_SEQ'
       RETURNING SEQ_COUNT 
       INTO GROUP_SEQ;
       COMMIT;

      INSERT INTO AAA (ID, SEQ) VALUES (ID, GROUP_SEQ);
      WHILE PP <= 4
      LOOP
         UPDATE YYY_SEQUENCE 
         SET SEQ_COUNT = SEQ_COUNT   1
         WHERE SEQ_NAME = 'TRANS_SEQ'
         RETURNING SEQ_COUNT 
         INTO TRANS_SEQ;
         COMMIT;

         IF (PP < 3) THEN
             DEBET := TRANS_SUM;
             CREDIT := 0;
         ELSE             
             DEBET := 0;
             CREDIT := TRANS_SUM;
         END IF;
         PP := PP  1;
         INSERT INTO BBB(ID, SEQ, UNIT, DEBET, CREDIT) VALUES (ID, TRANS_SEQ, UNIT, DEBET, CREDIT);
         COMMIT;
      END LOOP;
   END LOOP;
PP :=1;
END LOOP;
END
 

Первая вставка дает мне все строки в данных d_rec. Но вторая вставка дает мне только первую строку данных d_rec.

Комментарии:

1. Не будет ли самая внутренняя петля вращаться вечно, так как PP она никогда не увеличивается? Хотя as KAS не определен, это все равно не может быть кодом, который вы на самом деле запускаете… Вы также можете захотеть PP вернуться к одному из них до этого самого внутреннего цикла, а не после d_rec цикла — возможно, поэтому вы получаете только одну вставку, предполагая, что есть только один блок из самого внешнего цикла; но это не ясно.

2. извините, код-это всего лишь фрагмент фактического кода. так что могут быть некоторые ошибки. Я отредактировал, чтобы скорректировать код. надеюсь, это будет легче понять.

3. извините, вы правы. Позиционирование PP, при котором вставляется только первая строка… thx..

Ответ №1:

Вы сбрасываете PP счетчик после d_rec цикла внутри v_rec цикла; это означает, что, как только он был увеличен до 4 для первого d_rec для единицы, последующие d_rec итерации пропускают самый внутренний цикл — потому PP <= 4 что для них это никогда не верно.

Быстрым решением было бы переместить этот сброс в цикл:

 ...
      END LOOP;
      -- reset PP after this loop
      PP :=1;
   END LOOP;
   -- instead of after this loop
   --PP :=1;
END LOOP;
END
 

Но, вероятно, было бы ясно, если бы вы сбросили настройки непосредственно перед его использованием:

 ...
      INSERT INTO AAA (ID, SEQ) VALUES (ID, GROUP_SEQ);
      -- reset here
      PP := 1;
      WHILE PP <= 4
      LOOP
         PP := PP  1;

         ...

         IF (PP < 3) THEN
             DEBET := TRANS_SUM;
             CREDIT := 0;
         ELSE             
             DEBET := 0;
             CREDIT := TRANS_SUM;
         END IF;

         INSERT INTO BBB(ID, SEQ, UNIT, DEBET, CREDIT) VALUES (ID, TRANS_SEQ, UNIT, DEBET, CREDIT);
         COMMIT;
      END LOOP;
   END LOOP;
END LOOP;
END
 

Или вообще избавьтесь от явной переменной — чтобы ее не нужно было объявлять, сбрасывать или увеличивать — и вместо этого используйте цикл for:

 ...
      INSERT INTO AAA (ID, SEQ) VALUES (ID, GROUP_SEQ);
      FOR PP IN 1..4
      LOOP
         ...

         IF (PP < 3) THEN
             DEBET := TRANS_SUM;
             CREDIT := 0;
         ELSE             
             DEBET := 0;
             CREDIT := TRANS_SUM;
         END IF;

         INSERT INTO BBB(ID, SEQ, UNIT, DEBET, CREDIT) VALUES (ID, TRANS_SEQ, UNIT, DEBET, CREDIT);
         COMMIT;
      END LOOP;
   END LOOP;
END LOOP;
END
 

Кстати, все эти коммиты выглядят неправильно — они делают невозможным перезапуск при сбое, но также негативно влияют на производительность. И вы, вероятно, могли бы упростить это до меньшего количества циклов.