AZ93 Ответов: 2

Циклическое прохождение хранимой процедуры - электронная почта


Я пишу хранимую процедуру, которая будет отправлять оповещения по электронной почте пользователям. Вы можете отправить только 200 пользователей по электронной почте одновременно. У меня есть более 1000 пользователей для отправки электронной почты, поэтому мне нужно перебирать таблицу и получать 200 пользователей одновременно. Как мне сделать этот цикл в sql?

У меня уже есть работа с электронной почтой, мне просто нужна помощь с циклом 200 пользователей каждый раз, пока он не закончится.


1. ИП вызовет таблицу и соберет всех пользователей для определенного объекта, затем нам нужно отправить электронные письма всем этим пользователям, и ИП пройдет через всех пользователей.

Что я уже пробовал:

CREATE PROCEDURE [dbo].[sp_emailAlertJob]
(
	@EMAILDESC INT = 1,
	@FACILITY VARCHAR(5) = 'TEST' 
)
--WITH ENCRYPTION
AS
BEGIN

DECLARE @SENDTO VARCHAR(4000)

DECLARE @Getusers CURSOR



	BEGIN
				
		SET @Getusers = CURSOR FOR
		SELECT TOP (2) EMAIL
		FROM [dbo].[Employee]
		WHERE FACILITY = @FACILITY  
		ORDER BY  TSG_RECORD_ID DESC

	END

		OPEN @Getusers
		FETCH NEXT FROM @Getusers INTO @SENDTO

			WHILE @@FETCH_STATUS = 0
			BEGIN
				BEGIN
					EXEC [sp_EmailAlert] @SENDTO,@EMAILDESC,@FACILITY
				END

			FETCH NEXT FROM @Getusers INTO @SENDTO

			END
		
		CLOSE @Getusers
		DEALLOCATE @Getusers

END

2 Ответов

Рейтинг:
2

Gerry Schmitz

Вам нужно отслеживать отправленные адреса (A); затем выберите топ-200 из B, а не из A.


Рейтинг:
2

CHill60

Я ненавижу курсоры, и это можно сделать и без них.

Создайте временную таблицу для регистрации вашего прогресса и обновляйте ее по мере отправки электронных писем.

DECLARE @SENDTOLIST TABLE (id int identity(1,1), sendto VARCHAR(4000), done bit)

INSERT INTO @SENDTOLIST(sendto, done)
SELECT EMAIL, 0 FROM @Employee WHERE FACILITY = @FACILITY  ORDER BY TSG_RECORD_ID
Затем просто используйте два цикла - внешний гарантирует, что вы охватите каждый элемент, который будет отправлен по электронной почте, а внутренний-200 писем
DECLARE @SENDTO VARCHAR(4000)
DECLARE @id INT
-- Loop until all items have been sent
WHILE EXISTS(SELECT TOP 1 done FROM @SENDTOLIST WHERE done = 0)
BEGIN
	-- Process 200 emails
	print 'Sending 200 emails'
	DECLARE @i INT = 1
	WHILE @i <= 200
	BEGIN
		SELECT TOP 1 @SENDTO=sendto, @id = id FROM @SENDTOLIST WHERE done = 0
		EXEC [sp_EmailAlert] @SENDTO,@EMAILDESC,@FACILITY
		UPDATE @SENDTOLIST SET done = 1 WHERE id = @id
		SET @i = @i + 1
	END
	-- Whatever you have to do to wait for the next slot for 200 emails
	print 'waiting for next slot'
END
Что нужно отметить:
Внешнее время зависит от того, что осталось обработать как минимум 1 элемент - это TOP 1 это не ошибка набора текста. Это покрывает количество писем, не являющихся точным кратным 200.
Аналогично, поскольку я использую цикл, а не курсор, я хочу читать только одну запись за раз. Так что в ту секунду TOP 1 это тоже не опечатка.