У меня есть блок кода, который я хочу использовать снова и снова в хранимой процедуре. Этот блок кода установит пустые значения для ряда переменных (''). Я хотел бы сделать это без необходимости каждый раз копировать/вставлять весь код.
Короче говоря, я использую одну хранимую процедуру для отправки множества уникальных электронных писем с различными таблицами, форматами и т. д.
Я добиваюсь этого, объявляя эти переменные в начале хранимой процедуры:
/* declare HTML variables */
declare @htmlSTART nvarchar(max), @htmlEND nvarchar(max), @body nvarchar(max), @greeting nvarchar(max), @closing nvarchar(max), @subject nvarchar(max)
declare @recipients nvarchar(max), @profile_name nvarchar(max), @body_format nvarchar(max), @copy_recipients nvarchar(max), @blind_copy_recipients nvarchar(max)
declare @table_header_01 nvarchar(max), @paragragh_01 nvarchar(max), @HTML_table_01 nvarchar(MAX), @disclaimer_01 nvarchar(max)
declare @table_header_02 nvarchar(max), @paragragh_02 nvarchar(max), @HTML_table_02 nvarchar(MAX), @disclaimer_02 nvarchar(max)
declare @table_header_03 nvarchar(max), @paragragh_03 nvarchar(max), @HTML_table_03 nvarchar(MAX), @disclaimer_03 nvarchar(max)
declare @table_header_04 nvarchar(max), @paragragh_04 nvarchar(max), @HTML_table_04 nvarchar(MAX), @disclaimer_04 nvarchar(max)
Затем хранимая процедура запрашивает набор данных, создает временную таблицу основных данных для электронных писем, рекурсивно извлекает каждый уникальный адрес электронной почты с помощью курсора, создает таблицы в формате HTML и отправляет соответствующие данные по электронной почте следующим образом:
set @body =
concat
(
@htmlSTART
, @greeting
, @paragragh_01, @table_header_01, @HTML_table_01
, @paragragh_02, @table_header_02, @HTML_table_02
, @paragragh_03, @table_header_03, @HTML_table_03
, @paragragh_04, @table_header_04, @HTML_table_04
, @closing
, @disclaimer_01
, @htmlEND
)
EXEC msdb.dbo.sp_send_dbmail
@profile_name = @profile_name
, @body = @body
, @body_format = @body_format
, @recipients = @recipients
, @copy_recipients = @copy_recipients
, @blind_copy_recipients = @blind_copy_recipients
, @subject = @subject
В начале каждого раздела электронного письма я устанавливаю пустые переменные:
set @table_header_01 = '' set @paragragh_01 = '' set @HTML_table_01 = '' set @disclaimer_01 = ''
set @table_header_02 = '' set @paragragh_02 = '' set @HTML_table_02 = '' set @disclaimer_02 = ''
set @table_header_03 = '' set @paragragh_03 = '' set @HTML_table_03 = '' set @disclaimer_03 = ''
set @table_header_04 = '' set @paragragh_04 = '' set @HTML_table_04 = '' set @disclaimer_04 = ''
Вместо того, чтобы запоминать, какие таблицы и т. д. удалить из set @body = для каждого электронного письма, я каждый раз сбрасываю переменные, потому что некоторые электронные письма будут содержать только одну таблицу (или ни одной), а некоторые — несколько таблиц. Если переменные @html_table пусты, это не испортит электронное письмо, но удаление неправильных переменных из set @body = испортит его, когда я EXEC msdb.dbo.sp_send_dbmail.
Я нашел ЭТУ ветку, в которой рассказывается о создании временных процедур, и я также попробовал динамический SQL, но, насколько я могу судить, динамический SQL не может устанавливать переменные из внешней области. Выдает ошибку о том, что переменные @HTML_table_01 и т. д. не были объявлены.
Есть ли способ повторно установить для всех переменных значение '', не копируя/вставляя/вводя их каждый раз? Если для этого существует хороший метод, я уверен, что для этого метода существует множество других приложений, помимо моего конкретного случая использования.
Согласен, это типичный метод. Обычно я просто назначаю переменные и использую их по мере необходимости. Однако в этом случае мне будет очень полезно установить их пустыми, чтобы не удалять их из моего set @body =, к которому я привык sp_send_dbmail. В этом конкретном случае для меня гораздо надежнее установить их пустыми перед каждым разделом.
Вы должны возложить на код, заполняющий каждую переменную, ответственность за присвоение значения NULL всем неиспользуемым переменным — когда вы объединяете их, значения NULL игнорируются.
Да, на самом деле мне следует установить для них значение null, а не пустое. Я тестировал с пустым значением, и все выглядело нормально, но для конкатенации все же лучше использовать значение null. В любом случае, я хотел бы найти способ (если возможно) быстро повторно использовать код. И в любом случае я изменю его, чтобы установить для них значение null, а не пустое. Спасибо.
Возможны грязные хаки, например, с использованием goto — вы можете иметь раздел инициализации переменной и перейти к нему с помощью goto, а также иметь другую переменную для хранения значения, чтобы определить, куда затем вернуться. Но от одной мысли об этом у меня стынет кровь; t-sql не похож на типичный императивный язык — если вам нужно повторить блок присвоения переменных, то пусть будет так; вы, вероятно, могли бы перепроектировать это, чтобы использовать временную таблицу, которую вы можете просто усечь и заполнить заново.
Сказано во время непонятного приступа кашля
@Stu, если вы хотите опубликовать свой комментарий о том, что грязные хаки возможны, но при этом у вас стынет кровь (я чувствую то же самое), а t-sql не является типичным императивным языком, я отмечу это как ответ. Спасибо за весь вклад.
sp_send_dbmail разработан как система оповещения для администраторов баз данных, а не как универсальное почтовое приложение. Вместо этого вам следует использовать подходящее почтовое решение.
@Charlieface, это не MailChimp, но он построен на основе ServiceBroker и довольно надежен. Так что это разумное решение, конечно, не для взаимодействия с клиентами, а для оповещения в масштабе предприятия.
@DavidBrowne-Microsoft Что бы вы ни говорили, но ведение журнала ужасно, а создание XHTML с использованием SQL довольно неприятно. Также отсутствуют многие параметры конфигурации, и работа TLS может раздражать. Даже C# или Powershell были бы намного лучше.
@Charlieface Придать таблицам красивый вид, добавить подписи, логотипы и т. д., конечно, было непросто, но я добился отличных результатов, используя sp_send_dbmail. Однако я открыт для альтернативных предложений. Я понимаю создание сценария PowerShell. Когда вы говорите C#, вы предлагаете создать приложение в Visual Studio или что-то в этом роде? Я ИТ-менеджер, но у меня очень маленькая команда и небольшая поддержка, а также существует неограниченный, постоянно расширяющийся океан ИТ-технологий и ресурсов, в которых сложно оставаться в курсе событий, занимаясь повседневной рутиной. Определенно готов научиться улучшать свои процессы.
Да, вы можете сделать это на C# или Powershell. Я уверен, что существуют библиотеки, которые могут генерировать для вас красивый HTML-код, а отправка электронной почты занимает всего несколько строк кода (возможно, больше для надежности и ведения журнала). Но похоже, вам нужен какой-то инструмент, например PowerAutomate.





Можно было бы реализовать грязный хак, например, используя goto — вы могли бы иметь раздел инициализации переменной и переходить к нему с помощью goto, а также иметь другую переменную для хранения значения, чтобы определить, куда затем вернуться, но я бы никогда не считал это вариант производственного кода; T-Sql не похож на типичный императивный язык — если вам нужно повторить блок присваиваний переменных, то пусть будет так.
Вместо набора повторяющихся похожих локальных переменных, возможно, рассмотрите #tempTable со столбцами, представляющими повторяющиеся переменные. Усеките его и заполните 4 (или любым количеством) строк для инициализации при каждом использовании.
только с идентификатором для представления каждого индекса переменной; будучи временной таблицей, вы даже можете поместить этот код инициализации в отдельную процедуру, которая будет иметь видимость временной таблицы.
Затем код, который присваивает переменную, может просто обновить таблицу для строки n, и вы сможете выбрать соответствующий столбец/строку для построения окончательной строки.
Или временная таблица с n строками и курсором.
Обычно вы просто назначаете все переменные вместо того, чтобы очищать их и затем присваивать.