powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / Oracle [игнор отключен] [закрыт для гостей] / PL SQL Обработка исключений в цикле
14 сообщений из 14, страница 1 из 1
PL SQL Обработка исключений в цикле
    #40087131
Maksim199809
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем привет! Первый раз задаю вопрос на форуме) Передо мной поставлена задача обновить существующие серии паспортов контактов, добавив пробел (Т.е. было 1234 - стало 12 34). Ключ на таблице по Серии + Номер. Сложность заключается в том, что в таблице так же присутствуют паспорта с правильным форматом серии, и могут возникать ситуации, когда есть два паспорта 1234 (серия) 56789 (номер) и 12 34 (серия) 56789 (номер). При попытке обновления первого паспорта возникнет ошибка, т.к. такая запись уже существует. В этом случае надо вместо обновления вызвать ее удаление. В самой базе более 100тыс строк. Я использую такой скрипт, но PLSQL выдает ошибку, что не ожидает EXCEPTION в этом месте, что можно сделать?

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
BEGIN
  DECLARE
    CURSOR cur_cleanup IS
    SELECT d.series from CX_SERIES_TEST d
    WHERE SERIES LIKE '____';
    TYPE t_row IS TABLE OF cur_cleanup%ROWTYPE;
    v_row t_row := t_row();
 BEGIN
   OPEN cur_cleanup;
   LOOP
    FETCH cur_cleanup BULK COLLECT INTO v_row LIMIT 100;
    EXIT WHEN v_row.COUNT = 0;
    FORALL d IN v_row.FIRST..v_row.LAST
      UPDATE CX_SERIES_TEST
      SET SERIES = substr(SERIES,1,2) || ' ' || substr(SERIES,3,4)
      where row_id = v_row(d).row_id;
    EXCEPTION
      WHEN DUP_VAL_ON_INDEX
      THEN
         BEGIN
            DELETE FROM CX_SERIES_TEST
            WHERE row_id = v_row(d).row_id;
        END;
     COMMIT;
 END LOOP;
CLOSE cur_cleanup;
END;
end;
/



Модератор: Оформляйте код с помощью тега SRC
...
Рейтинг: 0 / 0
PL SQL Обработка исключений в цикле
    #40087136
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
1. Используйте тег SRC.
2. Кто Вам сказал, что в FORALL можно таким образом обрабатывать Exception?
3. Нет ключевого слова BEGIN перед блоком с EXCEPTION
4. Многострочный update (bulk collect, forall) и Exception - .... как-то для новичка перебор.

p.s.
смотрю в доку и вижу
https://docs.oracle.com/database/121/LNPLS/forall_statement.htm#LNPLS01321
https://docs.oracle.com/database/121/LNPLS/tuning.htm#GUID-DAF46F06-EF3F-4B1A-A518-5238B80C69FA

Дока Handling FORALL Exceptions After FORALL Statement Completes

To allow a FORALL statement to continue even if some of its DML statements fail, include the SAVE EXCEPTIONS clause. When a DML statement fails, PL/SQL does not raise an exception; instead, it saves information about the failure. After the FORALL statement completes, PL/SQL raises a single exception for the FORALL statement (ORA-24381).
...
...
Рейтинг: 0 / 0
PL SQL Обработка исключений в цикле
    #40087138
dmdmdm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Чисто косметические правки, логику проверяйте сами.


Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
DECLARE

  CURSOR cur_cleanup IS
    SELECT d.series from CX_SERIES_TEST d WHERE SERIES LIKE '____';
  TYPE t_row IS TABLE OF cur_cleanup%ROWTYPE;
  v_row t_row := t_row();

BEGIN
  OPEN cur_cleanup;
  LOOP
    BEGIN
      FETCH cur_cleanup BULK COLLECT
        INTO v_row LIMIT 100;
      EXIT WHEN v_row.COUNT = 0;
      FORALL d IN v_row.FIRST .. v_row.LAST
        UPDATE CX_SERIES_TEST
           SET SERIES = substr(SERIES, 1, 2) || ' ' || substr(SERIES, 3, 4)
         where row_id = v_row(d).row_id;
    EXCEPTION
      WHEN DUP_VAL_ON_INDEX THEN
        DELETE FROM CX_SERIES_TEST WHERE row_id = v_row(d).row_id;
    END;
    --COMMIT; -- прежде чем коммитить, проверьте результат
  END LOOP;
  CLOSE cur_cleanup;
END;
...
Рейтинг: 0 / 0
PL SQL Обработка исключений в цикле
    #40087140
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dmdmdm,

Не взлетит. Слона то Вы и не заметили. Топикстартер программирует на каком-то алтернативном Oracle, с альтернативным Pl/SQL и альтернативной обработкой исключении при bulk операциях. Возможно какой-то импортозамещенный клон, не имеющий аналогов.

Документация от "обычного" Oracle о таких возможностях даже и не подозревает )))

IMHO могу, конечно, ошибаться.
...
Рейтинг: 0 / 0
PL SQL Обработка исключений в цикле
    #40087141
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dmdmdm,

имхо
EXCEPTION для FORALL c SAVE EXCEPTIONS
надо обрабатывать в цикле
аля FOR i IN 1..SQL%BULK_EXCEPTIONS.COUNT LOOP

.....
stax
...
Рейтинг: 0 / 0
PL SQL Обработка исключений в цикле
    #40087184
SQL*Plus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maksim199809
Всем привет! Первый раз задаю вопрос на форуме) Передо мной поставлена задача обновить существующие серии паспортов контактов, добавив пробел (Т.е. было 1234 - стало 12 34). Ключ на таблице по Серии + Номер. Сложность заключается в том, что в таблице так же присутствуют паспорта с правильным форматом серии, и могут возникать ситуации, когда есть два паспорта 1234 (серия) 56789 (номер) и 12 34 (серия) 56789 (номер). При попытке обновления первого паспорта возникнет ошибка, т.к. такая запись уже существует. В этом случае надо вместо обновления вызвать ее удаление. В самой базе более 100тыс строк. Я использую такой скрипт, но PLSQL выдает ошибку, что не ожидает EXCEPTION в этом месте, что можно сделать?
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
BEGIN
  DECLARE
    CURSOR cur_cleanup IS
    SELECT d.series from CX_SERIES_TEST d
    WHERE SERIES LIKE '____';
    TYPE t_row IS TABLE OF cur_cleanup%ROWTYPE;
    v_row t_row := t_row();
 BEGIN
   OPEN cur_cleanup;
   LOOP
    FETCH cur_cleanup BULK COLLECT INTO v_row LIMIT 100;
    EXIT WHEN v_row.COUNT = 0;
    FORALL d IN v_row.FIRST..v_row.LAST
      UPDATE CX_SERIES_TEST
      SET SERIES = substr(SERIES,1,2) || ' ' || substr(SERIES,3,4)
      where row_id = v_row(d).row_id;
    EXCEPTION
      WHEN DUP_VAL_ON_INDEX
      THEN
         BEGIN
            DELETE FROM CX_SERIES_TEST
            WHERE row_id = v_row(d).row_id;
        END;
     COMMIT;
 END LOOP;
CLOSE cur_cleanup;
END;
end;
/


Для оформления кода используйте, пожалуйста, тэг SRC.
...
Рейтинг: 0 / 0
PL SQL Обработка исключений в цикле
    #40087269
Никанор Кузьмич
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А зачем так сложно? Можно ж проще:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
begin
  DBMS_ERRLOG.CREATE_ERROR_LOG('CX_SERIES_TEST');
end;
/

begin
  update CX_SERIES_TEST set SERIES = substr(SERIES,1,2) || ' ' || substr(SERIES,3,4)
  log errors into err$_CX_SERIES_TEST reject limit unlimited;

  delete from CX_SERIES_TEST
  where SERIES in (select SERIES from CX_SERIES_TEST);
end;
/


Ну это общая идея, детали можно потом дополнительно обработать напильником.
...
Рейтинг: 0 / 0
PL SQL Обработка исключений в цикле
    #40087293
Вячеслав Любомудров
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Может просто сначала удалить мешающие?
Код: plsql
1.
delete from tab where (ser,  num) in (select substr(ser, 1, 2)||substr(ser, 4, 2), num from tab where ser like '__ __')
...
Рейтинг: 0 / 0
PL SQL Обработка исключений в цикле
    #40087596
Фотография softwarer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maksim199809
что можно сделать?

Можно сделать просто и прямо.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
delete
from
    cx_series_test t
where
    length(t.series) > 4
    and
    exists
        (
            select
                1
            from
                cx_series_test t2
            where
                length(t.series = 4)
                and t.number = t2.number
                and t.series = substr(t2.series, 1, 2) || ' ' || substr(t.series, 3, 2)
        );

update
    cx_series_test
set
    series = substr(series, 1, 2) || ' ' || substr(series, 3, 2)
where
    length(series) = 4;
...
Рейтинг: 0 / 0
PL SQL Обработка исключений в цикле
    #40087641
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
softwarer
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
delete
from
    cx_series_test t
where
    length(t.series) > 4
    and
    exists
        (
            select
                1
            from
                cx_series_test t2
            where
                length(t.series = 4)
                and t.number = t2.number
                and t.series = substr(t2.series, 1, 2) || ' ' || substr(t.series, 3, 2)
        );

update
    cx_series_test
set
    series = substr(series, 1, 2) || ' ' || substr(series, 3, 2)
where
    length(series) = 4;

Сандерс, скажи честно, как ты и твои коллеги понимают, где заканчивается одна команда и начинается другая?
По пустой строке?!
...
Рейтинг: 0 / 0
PL SQL Обработка исключений в цикле
    #40087648
Фотография softwarer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Elic
Сандерс, скажи честно, как ты и твои коллеги понимают, где заканчивается одна команда и начинается другая?
По пустой строке?!

Не могу. Мне этот code style кажется издевательством над разработчиком. Но поскольку единый стиль таки лучше, чем "каждый как ему вздумается", я навалял форматизатор, который делает это издевательство за меня, и особо о том не думаю.
...
Рейтинг: 0 / 0
PL SQL Обработка исключений в цикле
    #40087650
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
softwarer
Мне этот code style кажется издевательством над разработчиком.
Код: plaintext
"Ёжики плакали, но продолжали есть кактус"
...
Рейтинг: 0 / 0
PL SQL Обработка исключений в цикле
    #40087723
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
softwarer

Можно сделать просто и прямо.

[/src]

он удаляет "короткие", "правильные" надо оставить (не оракловский "merge")

авторВ этом случае надо вместо обновления вызвать ее удаление.


.....
stax
...
Рейтинг: 0 / 0
PL SQL Обработка исключений в цикле
    #40088118
oragraf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Elic
Сандерс, скажи честно, как ты и твои коллеги понимают, где заканчивается одна команда и начинается другая?
По пустой строке?!
По точке с запятой, это же очевидно)
...
Рейтинг: 0 / 0
14 сообщений из 14, страница 1 из 1
Форумы / Oracle [игнор отключен] [закрыт для гостей] / PL SQL Обработка исключений в цикле
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]