Для того, что вы пытаетесь сделать, LOOP внутри LOOP будет правильным решением. Нет необходимости в дорогостоящей обработке исключений.
Тестовая настройка:
CREATE TEMP TABLE usr (id int, dummy text);
INSERT INTO usr VALUES
(1,'foo')
,(2,'bar')
,(3,'baz')
,(4,'blarg');
Функция:
CREATE OR REPLACE FUNCTION x.foo()
RETURNS VOID AS
$BODY$
DECLARE
_r record;
_dummy integer := 0;
_ct integer := 0;
_5mod_ct integer;
BEGIN
RAISE INFO 'Start... ';
FOR _r IN
SELECT * FROM usr WHERE id < 50 LIMIT 10
LOOP
LOOP
UPDATE usr SET dummy = 'foo' WHERE id = _r.id;
_ct := _ct + 1;
_5mod_ct := 5 % _ct;
EXIT WHEN _5mod_ct > 0; -- make sure this will be TRUE eventually!
RAISE INFO '_5mod_ct = 0; repeating UPDATE!';
END LOOP;
_dummy := 10 / _5mod_ct;
RAISE NOTICE '_5mod_ct: %, _dummy: %, user.id: %',
_5mod_ct, _dummy, _r.id;
END LOOP;
RAISE INFO 'Finished.';
END;
$BODY$ LANGUAGE plpgsql;
Звоните:
SELECT foo()
Выход:
INFO: Start...
INFO: _5mod_ct = 0; repeating UPDATE!
NOTICE: _5mod_ct: 1, _dummy: 10, user.id: 1
NOTICE: _5mod_ct: 2, _dummy: 5, user.id: 2
NOTICE: _5mod_ct: 1, _dummy: 10, user.id: 3
INFO: _5mod_ct = 0; repeating UPDATE!
NOTICE: _5mod_ct: 5, _dummy: 2, user.id: 4
INFO: Finished.
В вашем примере кода отображается ряд проблем:
Не используйте зарезервированные слова в качестве идентификаторов. user
- это зарезервированное слово в каждом стандарте SQL и, в частности, в PostgreSQL . Это плохая практика называть вашу таблицу "пользователь". Двойные кавычки делают это возможным. Это не значит, что это хорошая идея.
Не объявляйте переменные с тем же именем, что и столбцы таблицы, которые вы используете в теле функции. Это очень легко приводит к конфликтам имен. dummy
- это переменная и имя столбца одновременно в вашем примере. Просто еще один заряженный ножной пистолет. Одна (произвольная) возможность заключается в добавлении префикса к переменным _
, как я демонстрирую.
A FOR
цикл , как я демонстрирую, намного проще, чем явная обработка курсора.