Использование курсоров: обработка набора данных построчно

Что такое курсоры и зачем они нужны? 🔍

Представьте, что у вас есть таблица с тысячами строк, и вам нужно обработать каждую запись индивидуально — например, проверить условия, модифицировать данные или вызвать хранимую процедуру. Вот здесь на помощь приходят курсоры!

Курсор — это объект SQL, который позволяет последовательно перебирать строки в результате запроса и выполнять операции над каждой из них отдельно. Это как "указатель" на текущую строку в наборе данных.

Когда использовать:

  • Когда нужно построчно обработать результаты запроса
  • Для сложных бизнес-логик, которые сложно реализовать одним запросом
  • При интеграции с прикладным кодом (например, Python или Java)

Анатомия курсора: 4 ключевых шага ⚙️

Работа с курсорами всегда следует определенному паттерну:

1. Объявление курсора

DECLARE cursor_name CURSOR FOR 
SELECT column1, column2 FROM table_name WHERE condition;

2. Открытие курсора

OPEN cursor_name;

3. Чтение данных

FETCH NEXT FROM cursor_name INTO @variable1, @variable2;

4. Закрытие и освобождение

CLOSE cursor_name;
DEALLOCATE cursor_name;

Практический пример: обработка заказов 🛒

Давайте рассмотрим реальный сценарий — нам нужно обработать все необработанные заказы старше 7 дней:

-- Создаем временные переменные
DECLARE @OrderId INT;
DECLARE @OrderDate DATETIME;
DECLARE @CustomerId INT;

-- Объявляем курсор
DECLARE order_cursor CURSOR FOR 
SELECT Id, OrderDate, CustomerId 
FROM Orders 
WHERE Status = 'Pending' AND OrderDate < DATEADD(day, -7, GETDATE());

-- Открываем курсор
OPEN order_cursor;

-- Начинаем обработку
FETCH NEXT FROM order_cursor INTO @OrderId, @OrderDate, @CustomerId;

WHILE @@FETCH_STATUS = 0
BEGIN
    -- Логика обработки для каждого заказа
    PRINT 'Обрабатывается заказ #' + CAST(@OrderId AS VARCHAR);

    -- Например, можно обновить статус
    UPDATE Orders SET Status = 'Expired' WHERE Id = @OrderId;

    -- Или вызвать хранимую процедуру
    EXEC sp_send_order_notification @CustomerId, @OrderId;

    -- Переходим к следующей записи
    FETCH NEXT FROM order_cursor INTO @OrderId, @OrderDate, @CustomerId;
END

-- Не забываем освободить ресурсы!
CLOSE order_cursor;
DEALLOCATE order_cursor;

Важные тонкости работы с курсорами 🧠

Производительность

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

Типы курсоров

  • STATIC: Создает копию данных в tempdb (менее производительно, но стабильно)
  • DYNAMIC: Отслеживает изменения в базовых таблицах
  • FAST_FORWARD: Оптимизирован для чтения только вперед (самый быстрый вариант)

Пример объявления с параметрами:

DECLARE fast_cursor CURSOR FAST_FORWARD FOR
SELECT * FROM LargeTable;

Альтернативы курсорам: когда что использовать 🔄

Ситуация Лучший подход
Обработка каждой строки с бизнес-логикой Курсор
Массовое обновление/удаление Один UPDATE/DELETE
Сложные вычисления по группам Оконные функции
Агрегация данных GROUP BY

Тест на понимание 💡

Попробуйте решить задачу: нужно пройтись по таблице Products и для товаров с ценой выше 1000 увеличить цену на 10%, а для остальных — на 5%. Напишите код с курсором, который это делает (ответ в следующем уроке!)

-- Ваше решение здесь

Заключительные мысли 🌟

Курсоры — мощный инструмент в руках SQL-разработчика, но как любой мощный инструмент, они требуют аккуратного обращения. Используйте их там, где действительно нужна построчная обработка, и всегда помните о производительности.

Скрыть рекламу навсегда

🌱 Индвидидулаьные занятия

Индивидуальные онлайн-занятия по программированию для детей и подростков

Личный подход, без воды, с фокусом на понимание и реальные проекты.

🚀 Записаться на занятие