Пример, когда нам нужно использовать курсор в SQL, который не может быть решен с помощью подходов, основанных на множестве

#sql #sql-server #tsql

#sql #sql-server #tsql

Вопрос:

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

Спасибо

Ответ №1:

Курсор часто используется, когда вам нужно выполнить действие для каждой строки. Это то, что мы часто относим к другим инструментам за пределами СУБД. В целом сила СУБД заключается в подходах, основанных на множествах для данных. Однако .. чтобы привести пример.

Допустим, у вас есть таблица, в которую какой-то другой процесс записывает почтовые сообщения, которые будут сохранены и отправлены позже. Возможно, запущено несколько заданий SQL, и каждое записывает свой собственный статус, затем, когда наступает следующее утро или загрузка сервера очень низкая, ожидается, что СУБД отправит их самостоятельно.

Настройка примерной таблицы с некоторыми данными:

 CREATE TABLE outgoingMessages
(
    recipient VARCHAR(MAX),
    subject NVARCHAR(255),
    message NVARCHAR(MAX)
)

INSERT INTO dbo.outgoingMessages (recipient,subject,message)
VALUES
('foo@bar.com', N'An email', N'Procedure dbo.Foo ran with statuscode X'),
('foo@bar.com', N'An email', N'Procedure dbo.Bar ran with statuscode Y'),
('manager@bar.com', N'An email', N'Data synchronisation had problems, ask foo')
  

Тогда в качестве теоретического конечного шага / конечного задания у нас есть процесс, который проходит через таблицу и обрабатывает все созданные сообщения.

 /* Scheduled job */ 
DECLARE mailCursor CURSOR FOR 
SELECT * FROM dbo.outgoingMessages;

DECLARE @mailRecipient VARCHAR(MAX); 
DECLARE @mailSubject NVARCHAR(255); 
DECLARE @mailMessage NVARCHAR(MAX);

OPEN mailCursor;

FETCH NEXT FROM mailCursor INTO 
@mailRecipient, @mailSubject, @mailMessage 

WHILE @@FETCH_STATUS = 0
BEGIN
  PRINT @mailRecipient   ' '   @mailSubject   ' '   @mailMessage

  EXEC msdb.dbo.sp_send_dbmail 
  @profile_name = N'defaultMailprofile',
  @recipients = @mailRecipient,
  @subject = @mailSubject,
  @body = @mailMessage


  FETCH NEXT FROM mailCursor INTO 
  @mailRecipient, @mailSubject, @mailMessage

END

CLOSE mailCursor; 
DEALLOCATE mailCursor;
  

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

 /* Print results */
foo@bar.com An email Procedure dbo.Foo ran with statuscode X
foo@bar.com An email Procedure dbo.Bar ran with statuscode Y
manager@bar.com An email Data synchronisation had problems, ask foo
  

Вы можете представить таблицу с, возможно, созданными вызовами API другими автоматизированными процессами, которые затем будут выполнены позднее.

Являются ли курсоры распространенными? Нет. Вы всегда должны учитывать их варианты использования и в идеале использовать другой подход. Но если вам нужно что-то сделать для каждой строки и, возможно, перейти назад в зависимости от условий. Курсоры позволяют вам делать это внутри СУБД, и они являются мощным инструментом.