Можно внести массовые изменения в код хранимой процедуры, но задача может быть довольно сложной из-за множества вариантов конструкций T-SQL.Простые замены строк могут работать в некоторых случаях, но являются хрупкими, поскольку заменяемый текст может встречаться в других контекстах, где его не следует изменять.Например, если ваш исходный профиль называется «mail», при замене простого текста также будет изменено имя процедуры «sp_send_dbmail».
Ниже приведен пример PowerShell, в котором используется Microsoft.SqlServer.TransactSql.ScriptDom сборка для более интеллектуального анализа кода T-SQL и внесения целевых изменений.Это не полное решение, которое может изменить все вхождения имени профиля (например, назначения локальной переменной, позиционные параметры sp_send_db_mail и т. Д.), Но изменит значение, указанное в sp_send_dbmail, с именем синтаксиса параметра и является более надежным, чем замена текста.Вы можете протестировать и настроить код в среде разработчика в соответствии с вашими потребностями.
Кроме того, в качестве заявления об отказе, изменение текста токена анализатора таким образом недокументировано, поэтому используйте его на свой страх и риск.
Function Replace-DatabaseMailProfileNames($script, $originalProfileName, $newProfileName) {
# use the appropriate TSqlParser version for the target SQL Server version
$parser = New-Object Microsoft.SqlServer.TransactSql.ScriptDom.TSql140Parser($true)
$parseErrors = New-Object System.Collections.Generic.List[Microsoft.SqlServer.TransactSql.ScriptDom.ParseError]
$scriptReader = New-Object System.IO.StringReader($script)
$fragment = $parser.Parse($scriptReader, [ref]$parseErrors)
$scriptChanged = $false
if($parseErrors.Count -eq 0) {
$fragment.Batches[0].Statements[0].ScriptTokenStream[$fragment.Batches[0].Statements[0].FirstTokenIndex].Text = "ALTER"
foreach($statement in $fragment.Batches[0].Statements[0].StatementList.Statements) {
switch($statement.GetType().ToString())
{
"Microsoft.SqlServer.TransactSql.ScriptDom.ExecuteStatement" {
if($statement.ExecuteSpecification.ExecutableEntity.ProcedureReference.ProcedureReference.Name.BaseIdentifier.Value.ToLower() -eq "sp_send_dbmail") {
foreach($parameter in $statement.ExecuteSpecification.ExecutableEntity.Parameters) {
if(($parameter.Variable.Name.ToLower() -eq "@profile_name") -and ($parameter.ParameterValue.Value.ToLower() -eq $originalProfileName.ToLower())) {
$parameter.ParameterValue.ScriptTokenStream[$parameter.ParameterValue.FirstTokenIndex].Text = $newProfileName
$scriptChanged = $true
}
}
}
break
}
}
}
if($scriptChanged) {
$fragmentText = New-Object System.Text.StringBuilder
# reconstrunct script from tokens containing new values
for($i = $fragment.FirstTokenIndex; $i -le $fragment.LastTokenIndex; ++$i) {
[void]$fragmentText.Append($fragment.ScriptTokenStream[$i].Text)
}
return $fragmentText.ToString()
}
else {
# return null to indicate script was not changed
return $null
}
}
else {
throw "Error(s) parsing script"
}
}
############
### main ###
############
# Specify path to Microsoft.SqlServer.TransactSql.ScriptDom.dll.
# This assembly is available from the Microsoft DacFx NuGet package: https://www.nuget.org/packages/Microsoft.SqlServer.DacFx.x64/
Add-Type -Path "C:\Temp\Microsoft.SqlServer.TransactSql.ScriptDom.dll"
$originalProfileName = "Original mail profile name"
$newProfileName = "'New mail profile name'"
try {
$connectionString = "Data Source=.;Initial Catalog=YourDatabase;Integrated Security=SSPI;MultipleActiveResultSets=True";
$connection = New-Object System.Data.SqlClient.SqlConnection($connectionString);
$query = @"
SELECT QUOTENAME(OBJECT_SCHEMA_NAME(p.object_id)) + '.' + QUOTENAME(p.name) AS procedure_name, sm.definition
FROM sys.procedures AS p
JOIN sys.sql_modules AS sm ON sm.object_id = p.object_id
WHERE sm.definition LIKE N'%sp_send_dbmail%';
"@
$selectCommand = New-Object System.Data.SqlClient.SqlCommand($query, $connection)
$connection.Open();
$reader = $selectCommand.ExecuteReader()
while($reader.Read()) {
$newScript = Replace-DatabaseMailProfileNames -script "$($reader["definition"])" -originalProfileName $originalProfileName -newProfileName $newProfileName
if($newScript -ne $null) {
$alterCommand = New-Object System.Data.SqlClient.SqlCommand($newScript, $connection)
[void]$alterCommand.ExecuteNonQuery()
"Stored procedure $($reader["procedure_name"]) changed"
}
}
}
catch {
throw
}