Come si chiama una procedura memorizzata di SQL Server da PowerShell?
-
01-07-2019 - |
Domanda
Ho un file CSV di grandi dimensioni e desidero eseguire una procedura memorizzata per ogni riga.
Qual è il modo migliore per eseguire una procedura memorizzata da PowerShell?
Soluzione
Questa risposta è stata estratta da http://www.databasejournal.com/features/mssql/article.php/3683181
Questo stesso esempio può essere utilizzato per qualsiasi query ad hoc.Eseguiamo la procedura memorizzata “sp_helpdb” come mostrato di seguito.
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=HOME\SQLEXPRESS;Database=master;Integrated Security=True"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "sp_helpdb"
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$SqlConnection.Close()
$DataSet.Tables[0]
Altri suggerimenti
Ecco una funzione che utilizzo (leggermente oscurata).Consente parametri di input e output.Ho implementato solo i tipi uniqueidentifier e varchar, ma qualsiasi altro tipo è facile da aggiungere.Se utilizzi procedure memorizzate parametrizzate (o semplicemente SQL parametrizzato... questo codice si adatta facilmente a questo), questo ti renderà la vita molto più semplice.
Per chiamare la funzione, è necessaria una connessione al server SQL (ad esempio $conn),
$res=exec-storedprocedure -storedProcName 'stp_myProc' -parameters @{Param1="Ciao";Param2=50} -outparams @{ID="uniqueidentifier"} $conn
recuperare l'output della procedura dall'oggetto restituito
$res.data #dataset contenente i datatable restituiti da selects
$res.outputparams.ID #ID parametro di output (identificatore univoco)
La funzione:
function exec-storedprocedure($storedProcName,
[hashtable] $parameters=@{},
[hashtable] $outparams=@{},
$conn,[switch]$help){
function put-outputparameters($cmd, $outparams){
foreach($outp in $outparams.Keys){
$cmd.Parameters.Add("@$outp", (get-paramtype $outparams[$outp])).Direction=[System.Data.ParameterDirection]::Output
}
}
function get-outputparameters($cmd,$outparams){
foreach($p in $cmd.Parameters){
if ($p.Direction -eq [System.Data.ParameterDirection]::Output){
$outparams[$p.ParameterName.Replace("@","")]=$p.Value
}
}
}
function get-paramtype($typename,[switch]$help){
switch ($typename){
'uniqueidentifier' {[System.Data.SqlDbType]::UniqueIdentifier}
'int' {[System.Data.SqlDbType]::Int}
'xml' {[System.Data.SqlDbType]::Xml}
'nvarchar' {[System.Data.SqlDbType]::NVarchar}
default {[System.Data.SqlDbType]::Varchar}
}
}
if ($help){
$msg = @"
Execute a sql statement. Parameters are allowed.
Input parameters should be a dictionary of parameter names and values.
Output parameters should be a dictionary of parameter names and types.
Return value will usually be a list of datarows.
Usage: exec-query sql [inputparameters] [outputparameters] [conn] [-help]
"@
Write-Host $msg
return
}
$close=($conn.State -eq [System.Data.ConnectionState]'Closed')
if ($close) {
$conn.Open()
}
$cmd=new-object system.Data.SqlClient.SqlCommand($sql,$conn)
$cmd.CommandType=[System.Data.CommandType]'StoredProcedure'
$cmd.CommandText=$storedProcName
foreach($p in $parameters.Keys){
$cmd.Parameters.AddWithValue("@$p",[string]$parameters[$p]).Direction=
[System.Data.ParameterDirection]::Input
}
put-outputparameters $cmd $outparams
$ds=New-Object system.Data.DataSet
$da=New-Object system.Data.SqlClient.SqlDataAdapter($cmd)
[Void]$da.fill($ds)
if ($close) {
$conn.Close()
}
get-outputparameters $cmd $outparams
return @{data=$ds;outputparams=$outparams}
}
Ecco una funzione che utilizzo per eseguire comandi SQL.Devi solo cambiare $sqlCommand.CommandText con il nome del tuo sproc e $SqlCommand.CommandType con CommandType.StoredProcedure.
function execute-Sql{
param($server, $db, $sql )
$sqlConnection = new-object System.Data.SqlClient.SqlConnection
$sqlConnection.ConnectionString = 'server=' + $server + ';integrated security=TRUE;database=' + $db
$sqlConnection.Open()
$sqlCommand = new-object System.Data.SqlClient.SqlCommand
$sqlCommand.CommandTimeout = 120
$sqlCommand.Connection = $sqlConnection
$sqlCommand.CommandText= $sql
$text = $sql.Substring(0, 50)
Write-Progress -Activity "Executing SQL" -Status "Executing SQL => $text..."
Write-Host "Executing SQL => $text..."
$result = $sqlCommand.ExecuteNonQuery()
$sqlConnection.Close()
}
Usa sqlcmd invece di osql se è un database del 2005
Consideriamo la possibilità di chiamare osql.exe (lo strumento da riga di comando per SQL Server) passando come parametro un file di testo scritto per ogni riga con la chiamata alla stored procedure.
SQL Server fornisce alcuni assembly che potrebbero essere utili con il nome SMO che si integrano perfettamente con PowerShell.Ecco un articolo a riguardo.
http://www.databasejournal.com/features/mssql/article.php/3696731
Esistono metodi API per eseguire procedure memorizzate che ritengo valga la pena indagare.Ecco un esempio di avvio:
http://www.eggheadcafe.com/software/aspnet/29974894/smo-running-a-stored-pro.aspx
Includo invoke-sqlcmd2.ps1
E write-datatable.ps1
da http://blogs.technet.com/b/heyscriptingguy/archive/2010/11/01/use-powershell-to-collect-server-data-and-write-to-sql.aspx.Le chiamate per eseguire comandi SQL assumono la forma: Invoke-sqlcmd2 -ServerInstance "<sql-server>" -Database <DB> -Query "truncate table <table>"
Un esempio di scrittura del contenuto delle variabili DataTable su una tabella SQL è simile a: $logs = (get-item SQLSERVER:\sql\<server_path>).ReadErrorLog()
Write-DataTable -ServerInstance "<sql-server>" -Database "<DB>" -TableName "<table>" -Data $logs
Li trovo utili quando si eseguono script PowerShell relativi al database SQL Server poiché gli script risultanti sono puliti e leggibili.