Можно ли изменить хранимую процедуру с помощью запроса в SQL Server? - PullRequest
0 голосов
/ 25 июня 2019

Мне нужно изменить имена профилей из всех хранимых процедур, имеющих оповещения по электронной почте. Можно ли изменить хранимую процедуру с помощью запроса в SQL Server.

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

SELECT object_definition(object_id) as [Proc Definition]
  , OBJECT_NAME(object_id) [Stored Proc Name]
FROM sys.objects 
WHERE type='P' and object_definition(object_id) like '%sp_send_dbmail%'

С помощью вышеприведенного запроса мне нужно изменить тело хранимой процедуры.

Ответы [ 2 ]

1 голос
/ 25 июня 2019

вам нужно запустить цикл, чтобы обновить все процедуры и получить код процедуры, используя sp_helptext, и сохранить его в строковой переменной.Замените строковое значение, которое вам нужно, в своей переменной, а затем используйте обновленную строковую переменную для запуска команды alter и обновления ваших процедур.

0 голосов
/ 25 июня 2019

Можно внести массовые изменения в код хранимой процедуры, но задача может быть довольно сложной из-за множества вариантов конструкций 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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...