JavaRush /Курсы /SQL SELF /Прерывание и продолжение циклов: EXIT, CONTINUE

Прерывание и продолжение циклов: EXIT, CONTINUE

SQL SELF
51 уровень , 2 лекция
Открыта

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

Прерывание цикла с помощью EXIT

Иногда выполнение цикла нужно завершить раньше, чем он сам достигнет конца. Это может быть вызвано, например, нахождением нужного значения, обнаружением ошибки или завершением итераций по какому-либо условию. В таких ситуациях мы применяем EXIT.

EXIT — это способ "сказать" циклу: "Хватит, ты сделал свою работу, пора остановиться".

Синтаксис EXIT невероятно прост:

EXIT WHEN условие;

Здесь ключевая фраза WHEN указывает, при каком условии выполнение цикла будет завершено. Если условие не указано, EXIT просто мгновенно завершает выполнение текущего цикла.

Пример: завершение цикла, когда найдено заданное значение

Допустим, у нас есть столбец с номерами студентов, и мы хотим найти студента с конкретным идентификатором. Как только студент найден, цикл нужно завершить.

DO $$
DECLARE
    student_id INT;
BEGIN
    FOR student_id IN 1..100 LOOP
        RAISE NOTICE 'Checking student ID: %', student_id;

        -- Если нашли нужного студента, завершаем цикл
        IF student_id = 42 THEN
            RAISE NOTICE 'Student with ID 42 found!';
            EXIT;
        END IF;
    END LOOP;
END $$;

В этом примере цикл перебирает числа от 1 до 100, проверяя каждого "студента". Как только ID 42 найден, цикл выводит сообщение и завершает выполнение.

Пропуск итерации с помощью CONTINUE

Бывают ситуации, когда внутри цикла нужно пропустить определённые итерации, но при этом продолжить выполнение следующей итерации. Это особенно полезно, если вы хотите игнорировать "ненужные" данные или пропустить шаги для специфических условий.

CONTINUE говорит: "Окей, это условие нас не устраивает, просто перейдём к следующей итерации".

CONTINUE работает по тому же принципу, что и EXIT, только вместо завершения цикла он пропускает текущую итерацию:

CONTINUE WHEN условие;

Если условие выполняется, текущая итерация завершится, и выполнение перейдёт к следующей.

Пример: пропуск чётных чисел

В этом примере будем перебирать числа от 1 до 10, но игнорировать чётные числа, выводя только нечётные.

DO $$
DECLARE
    num INT;
BEGIN
    FOR num IN 1..10 LOOP
        -- Пропускаем чётные числа
        IF num % 2 = 0 THEN
            CONTINUE;
        END IF;

        RAISE NOTICE 'Odd number: %', num;
    END LOOP;
END $$;

Здесь CONTINUE пропускает все итерации, где num % 2 = 0 (т.е. число чётное). Как результат, в лог будут выведены только нечётные числа.

Комбинирование EXIT и CONTINUE

EXIT и CONTINUE можно использовать вместе, чтобы управлять циклом более гибко. Например, вы можете пропускать ненужные итерации с помощью CONTINUE, но завершать весь цикл, если найдено что-то важное.

Вот пример, где мы пропускаем все числа, кратные 3, но завершаем цикл, как только достигаем числа 15.

DO $$
DECLARE
    num INT;
BEGIN
    FOR num IN 1..20 LOOP
        -- Пропускаем числа, кратные 3
        IF num % 3 = 0 THEN
            CONTINUE;
        END IF;

        -- Завершаем цикл, если число равно 15
        IF num = 15 THEN
            RAISE NOTICE 'Stopping at number %', num;
            EXIT;
        END IF;

        RAISE NOTICE 'Current number: %', num;
    END LOOP;
END $$;

Здесь цикл работает следующим образом:

  • Числа, кратные 3, пропускаются (CONTINUE).
  • Если число равно 15, цикл завершает выполнение (EXIT).
  • Все остальные числа выводятся.

Продвинутый пример: пропуск некорректных данных и завершение при критической ошибке

Теперь давайте представим более реальную задачу. Мы хотим обработать список студентов, проверяя их данные. Некорректные записи будем пропускать, а в случае "критической ошибки" прекращать обработку.

DO $$
DECLARE
    student RECORD;
BEGIN
    FOR student IN
        SELECT * FROM students
    LOOP
        -- Пропускаем записи с некорректными данными
        IF student.name IS NULL THEN
            RAISE NOTICE 'Skipping student with ID %: Missing name', student.id;
            CONTINUE;
        END IF;

        -- Завершаем цикл при критической ошибке
        IF student.status = 'ERROR' THEN
            RAISE EXCEPTION 'Critical error for student ID %', student.id;
            EXIT; -- Эта строка фактически будет избыточной, так как RAISE EXCEPTION завершает выполнение.
        END IF;

        -- Обработка записи
        RAISE NOTICE 'Processing student: %', student.name;
    END LOOP;
END $$;

В этом примере CONTINUE помогает пропустить студентов с отсутствующим именем, а EXIT (вместе с RAISE EXCEPTION) завершает цикл при обнаружении серьёзной ошибки.

Практические советы и типичные ошибки

Не забывайте о логике условий. Неправильное использование условных выражений внутри EXIT WHEN или CONTINUE WHEN может привести к неожиданному поведению. Например, цикл может завершиться раньше времени или пропустить важные данные.

Чрезмерное использование CONTINUE. Если ваш код полон проверок с CONTINUE, возможно, стоит пересмотреть логику цикла, чтобы сделать её проще.

Не путайте EXIT и RETURN. EXIT завершает только текущий цикл, в то время как RETURN завершает выполнение функции целиком.

Будьте осторожны с бесконечными циклами. Если вы используете цикл LOOP без чёткого условия завершения, забудьте об EXIT, и ваш цикл может работать бесконечно.

2
Задача
SQL SELF, 51 уровень, 2 лекция
Недоступна
Пропуск и завершение цикла для обработки списка студентов
Пропуск и завершение цикла для обработки списка студентов
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ