SE の雑記

SQL Server の情報をメインに Microsoft 製品の勉強内容を日々投稿

PowerShell から SQLCMD.exe で SQL を実行

leave a comment

PowerShell から SQL Server に SQL を実行する場合、データベース エンジン PowerShell を使用することがあるかと思います。

ほかにも System.Data.SqlClient を使用した方法 (Windows PowerShell: Windows PowerShell からデータベースにアクセスする) や、SQLSMO を使用した方法 (Using PowerShell with SQL Server Management Objects (SMO)) もあります。

今回は、データベースエンジン PowerShell の Invoke-Sqlcmd を sqlcmd.exe に置き換えた際のメモを。
以下の情報を参考にさせていただいています。

SQL2005のSQLCMDオプションについて質問
Passing varibles with special characters and or embedded spaces in powershell 2.0 with SQL Server
How to stop the “Changed database context to …” message

Invoke-Sqlcmd を使用する場合、

Import-Module SQLPS -DisableNameChecking

を実行してモジュールをインポートして利用するかと思います。

バッチ等から実行する場合、この Import-Module の実行時間と CPU の使用率がそれなりに高く、数秒で結果を返すのが難しそうでしたので、SQLCMD.exe で置き換えを行いました。

# 外部の SQL ファイルを変数置換を使用して実行していたので、SQLCMD.exe への置き換えが影響が少ないと思いまして。

今回は以下のような sql ファイルを実行してみたいと思います。

USE $(DBNAME)
GO
SELECT TOP 10 name,type_desc FROM sys.tables

実行すると以下のような形式で結果が帰ってきます。

image

sqlcmd.exe からの実行結果は文字列として取得されます。

また、ヘッダーや処理対象行が出力されていますので、この状態では取得した結果が使いづらいかと。

ということでまずは SQL  を以下のように修正します。

SET NOCOUNT ON
GO
USE $(DBNAME)
GO
SELECT TOP 10 name,type_desc FROM sys.tables

 

次に PowerShell を以下のように修正します。

$header = "name","type_desc"
$ret = sqlcmd.exe -S . -E -i C:tempSQLCMDTest.sql -v DBNAME='ADK' -h -1 -m 1 -s "," | ConvertFrom-Csv -Delimiter "," -Header $header
$ret

 

そうすると実行結果を PSCustomObject で取得することができますので、後続の処理がしやすくなるかと思います。

image

ただし、変数の内容にスペースが入った場合は [無効な引数です。] のエラーが発生し実行することができませんでし た。綺麗な回避方法がわからず、cmd.exe 経由で実行することでエラーを回避することにしました。

$header = "name","type_desc"
$ret = cmd.exe /C "sqlcmd.exe -S . -E -i C:tempSQLCMDTest.sql -v DBNAME=`"TEST DB`" -h -1 -m 1 -s `",`"" | ConvertFrom-Csv -Delimiter "," -Header $header
$ret

 

外部の SQL ファイルを実行したほうがクエリ修正が楽なので、Invoke-sqlcmd でインプットファイルを使用していたのですが、効率よくクエリを実行する方法を考えないとな~と思いました。

追記

@mutaguchi さんにパラメーター解析モードを cmd 互換にする方法 (?% の利用) を教えていただきました。

以下の形式にすることで cmd.exe を介さずに実行できました。

$header = "name","type_desc"
$ret = sqlcmd.exe --% -S . -E -i C:tempSQLCMDTest.sql -v DBNAME="TEST DB" -h -1 -m 1 -s "," | ConvertFrom-Csv -Delimiter "," -Header $header
$ret
Share

Written by Masayuki.Ozawa

5月 27th, 2014 at 8:29 am

Posted in PowerShell,SQL Server

Tagged with ,

Leave a Reply