У меня есть простой запрос, который я запускаю, чтобы отправлять уведомления по электронной почте администраторам учетных записей AD, если учетные записи отключены более 30 дней. Он отлично работает, когда я запускаю его самостоятельно, вошел в систему как SA, но он не работает при запуске внутри заданий агента SQL Server.
Вот запрос с замененными бизнес-элементами и именами объектов:
DECLARE @QueryString varchar(max)
SET @QueryString = 'Select TrackingTable.Username FROM dbName.Schema.TrackingTable inner join dbName.Schema.viewName on DisabledAccounts.username = viewName.username WHERE DATEDIFF(dd,DateDisabled,GETDATE()) > 25 AND viewName.OU = ''InactiveAccounts'''
EXEC msdb.dbo.sp_send_dbmail @profile_name = 'Profile', @body = 'This is the body text. Nothing interesting here.
', @recipients = 'me@mydomain.tld', @subject='Account status update', @query = @QueryString, @importance = 'High'
Когда я запускаю его как SA, сообщение отправляется. Внутри задания агента SQL Server я получаю эту ошибку:
Executed as user: DOMAIN\MemberOfDomainAdmins. Error formatting query, probably invalid parameters [SQLSTATE 42000] (Error 22050). The step failed.
Пользователю домена, под которым выполняется задание, назначается роль db_owner в msdb и база данных, используемая для запроса, прикрепленного к сообщению. Его схема по умолчанию для обеих баз данных - dbo.
Ему также назначена роль системного администратора на сервере, и он является членом DatabaseMailuserRole в msdb. Он также имеет частный и публичный доступ к профилю почты базы данных, используемому запросом.
Я видел десятки примеров одной и той же проблемы в Интернете, но я уже предпринял шаги, которые исправили эту проблему в примерах, которые я видел. Что еще можно попробовать?
Я понял это сегодня утром. Проблема была в DATEADD
функция. Когда он находится внутри оператора EXECUTE (именно так его запускает задание агента SQL Server), интервал должен быть определенной датой (день), а не одним из токенов («дд»).
Итак, эта функция:DATEDIFF(dd,DateDisabled,GETDATE())
Нужно было больше так: DATEDIFF(day,DateDisabled,GETDATE())
Там было несколько вызовов этой функции, но идею вы поняли.
Вот как я это понял: у меня SQL Server Management Studio записал задание как сценарий CREATE в новом документе редактора запросов. Как только я нашел шаг, который пытался выполнить, я скопировал его. Сочные кусочки выглядят примерно так:
@command = N'[my query]'
Я скопировал эту группу строк в новое окно и добавил DECLARE для командной переменной.
Наконец, я использовал EXECUTE (@command) AS USER = '[the user the job runs as]'
чтобы увидеть, что произойдет. Выполнив запрос таким образом, я получил много более подробные сообщения об ошибках, чем я сделал из журнала для работы.
Я исправил это сейчас, и работа выполняется отлично.