Повторите блок кода в хранимой процедуре без повторного ввода

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

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

Я добиваюсь этого, объявляя эти переменные в начале хранимой процедуры:

/* 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 и т. д. не были объявлены.

Есть ли способ повторно установить для всех переменных значение '', не копируя/вставляя/вводя их каждый раз? Если для этого существует хороший метод, я уверен, что для этого метода существует множество других приложений, помимо моего конкретного случая использования.

Обычно вы просто назначаете все переменные вместо того, чтобы очищать их и затем присваивать.

David Browne - Microsoft 14.09.2023 22:57

Согласен, это типичный метод. Обычно я просто назначаю переменные и использую их по мере необходимости. Однако в этом случае мне будет очень полезно установить их пустыми, чтобы не удалять их из моего set @body =, к которому я привык sp_send_dbmail. В этом конкретном случае для меня гораздо надежнее установить их пустыми перед каждым разделом.

Sabatino Ognibene 14.09.2023 23:15

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

Stu 14.09.2023 23:23

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

Sabatino Ognibene 14.09.2023 23:26

Возможны грязные хаки, например, с использованием goto — вы можете иметь раздел инициализации переменной и перейти к нему с помощью goto, а также иметь другую переменную для хранения значения, чтобы определить, куда затем вернуться. Но от одной мысли об этом у меня стынет кровь; t-sql не похож на типичный императивный язык — если вам нужно повторить блок присвоения переменных, то пусть будет так; вы, вероятно, могли бы перепроектировать это, чтобы использовать временную таблицу, которую вы можете просто усечь и заполнить заново.

Stu 14.09.2023 23:29

Сказано во время непонятного приступа кашля

Stu 14.09.2023 23:40

@Stu, если вы хотите опубликовать свой комментарий о том, что грязные хаки возможны, но при этом у вас стынет кровь (я чувствую то же самое), а t-sql не является типичным императивным языком, я отмечу это как ответ. Спасибо за весь вклад.

Sabatino Ognibene 14.09.2023 23:44
sp_send_dbmail разработан как система оповещения для администраторов баз данных, а не как универсальное почтовое приложение. Вместо этого вам следует использовать подходящее почтовое решение.
Charlieface 15.09.2023 01:41

@Charlieface, это не MailChimp, но он построен на основе ServiceBroker и довольно надежен. Так что это разумное решение, конечно, не для взаимодействия с клиентами, а для оповещения в масштабе предприятия.

David Browne - Microsoft 15.09.2023 04:22

@DavidBrowne-Microsoft Что бы вы ни говорили, но ведение журнала ужасно, а создание XHTML с использованием SQL довольно неприятно. Также отсутствуют многие параметры конфигурации, и работа TLS может раздражать. Даже C# или Powershell были бы намного лучше.

Charlieface 15.09.2023 12:46

@Charlieface Придать таблицам красивый вид, добавить подписи, логотипы и т. д., конечно, было непросто, но я добился отличных результатов, используя sp_send_dbmail. Однако я открыт для альтернативных предложений. Я понимаю создание сценария PowerShell. Когда вы говорите C#, вы предлагаете создать приложение в Visual Studio или что-то в этом роде? Я ИТ-менеджер, но у меня очень маленькая команда и небольшая поддержка, а также существует неограниченный, постоянно расширяющийся океан ИТ-технологий и ресурсов, в которых сложно оставаться в курсе событий, занимаясь повседневной рутиной. Определенно готов научиться улучшать свои процессы.

Sabatino Ognibene 15.09.2023 23:48

Да, вы можете сделать это на C# или Powershell. Я уверен, что существуют библиотеки, которые могут генерировать для вас красивый HTML-код, а отправка электронной почты занимает всего несколько строк кода (возможно, больше для надежности и ведения журнала). Но похоже, вам нужен какой-то инструмент, например PowerAutomate.

Charlieface 18.09.2023 02:30
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
12
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Можно было бы реализовать грязный хак, например, используя goto — вы могли бы иметь раздел инициализации переменной и переходить к нему с помощью goto, а также иметь другую переменную для хранения значения, чтобы определить, куда затем вернуться, но я бы никогда не считал это вариант производственного кода; T-Sql не похож на типичный императивный язык — если вам нужно повторить блок присваиваний переменных, то пусть будет так.

Вместо набора повторяющихся похожих локальных переменных, возможно, рассмотрите #tempTable со столбцами, представляющими повторяющиеся переменные. Усеките его и заполните 4 (или любым количеством) строк для инициализации при каждом использовании. только с идентификатором для представления каждого индекса переменной; будучи временной таблицей, вы даже можете поместить этот код инициализации в отдельную процедуру, которая будет иметь видимость временной таблицы.

Затем код, который присваивает переменную, может просто обновить таблицу для строки n, и вы сможете выбрать соответствующий столбец/строку для построения окончательной строки.

Или временная таблица с n строками и курсором.

David Browne - Microsoft 15.09.2023 01:20

Другие вопросы по теме

Как сравнить несколько записей в нескольких строках для одного и того же идентификатора?
Частота значения в таблице
Если табличные переменные имеют область действия только своего пакета, то почему я могу выбрать одну из них после использования GO?
Какие замены регулярных выражений помогают при переписывании SQL-запросов MS Access как простых запросов TSQL? Как их можно зациклить с помощью Excel в качестве входных и выходных данных?
Max() и Min() имеют разное поведение?
Обновить столбец SQL на основе остатка, перенесенного из предыдущих строк
Пометить всех руководителей на собрании на основе дерева организации
Два элемента с одинаковым именем для пути xml()
Как объединить сценарий T-SQL с подстановочным знаком и сделать его более динамичным?
Посчитайте только рабочие дни (исключая выходные и праздничные дни) и добавьте фильтр, соответствующий запросу

Похожие вопросы

Как сравнить несколько записей в нескольких строках для одного и того же идентификатора?
Есть ли способ перенести значение ProcessDate в первую таблицу на основе совокупного итога столбца в другой таблице?
Частота значения в таблице
Отметьте условие «Не» в двух столбцах
Запрос занимает 10 минут при использовании табличных переменных по сравнению с 2 секундами при использовании временной таблицы
Невозможно разрешить конфликт параметров сортировки между «Polish_CI_AS» и «SQL_Latin1_General_CP1_CI_AS» в операторе CASE, возникающем в инструкции SELECT
Если табличные переменные имеют область действия только своего пакета, то почему я могу выбрать одну из них после использования GO?
Как сохранить несколько строк таблицы в разных переменных с помощью хранимой процедуры
Вызов хранимой процедуры со строковым выходным параметром
Попытка подсчитать последовательные значения для пользователя в медленно меняющейся таблице измерений, если последняя запись имеет определенное значение