#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
она никогда не увеличивается? Хотя asKAS
не определен, это все равно не может быть кодом, который вы на самом деле запускаете… Вы также можете захотеть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
Кстати, все эти коммиты выглядят неправильно — они делают невозможным перезапуск при сбое, но также негативно влияют на производительность. И вы, вероятно, могли бы упростить это до меньшего количества циклов.