web-dev-qa-db-ja.com

sqlcmdを使用してSQL ServerからCSV形式でデータをエクスポートするにはどうすればよいですか?

次のようなテキストファイルにデータを簡単にダンプできます。

sqlcmd -S myServer -d myDB -E -Q "select col1, col2, col3 from SomeTable" 
     -o "MyData.txt"

ただし、SQLCMDのヘルプファイルを見ましたが、CSV専用のオプションは見ていません。

SQLCMDを使用して、テーブルのデータをCSVテキストファイルにダンプする方法はありますか?

114
Ray Vega

次のようなものを実行できます。

sqlcmd -S MyServer -d myDB -E -Q "select col1, col2, col3 from SomeTable" 
       -o "MyData.csv" -h-1 -s"," -w 700
  • -h-1は結果から列名ヘッダーを削除します
  • -s","は列セパレーターをに設定します
  • -w 700は行の幅を700文字に設定します(これは最も長い行と同じ幅にする必要があります。そうしないと、次の行に折り返されます)
121
scottm
sqlcmd -S myServer -d myDB -E -o "MyData.txt" ^
    -Q "select bar from foo" ^
    -W -w 999 -s","

最後の行には、CSV固有のオプションが含まれています。

  • -W individual各フィールドから末尾のスペースを削除します
  • -s","は、列セパレーターをコンマ(、)に設定します
  • -w 999は行幅を999文字に設定します

scottmの答え は私が使用しているものに非常に近いですが、私は-Wが本当に素晴らしい追加であることがわかりました:CSVを他の場所で消費するときに空白をトリミングする必要はありません。

MSDN sqlcmdリファレンス も参照してください。 /?オプションの出力を恥じます。

63
ESV

これはbcpが意図したものではありませんか?

bcp "select col1, col2, col3 from database.schema.SomeTable" queryout  "c:\MyData.txt"  -c -t"," -r"\n" -S ServerName -T

コマンドラインからこれを実行して、構文を確認してください。

bcp /?

例えば:

usage: bcp {dbtable | query} {in | out | queryout | format} datafile
  [-m maxerrors]            [-f formatfile]          [-e errfile]
  [-F firstrow]             [-L lastrow]             [-b batchsize]
  [-n native type]          [-c character type]      [-w wide character type]
  [-N keep non-text native] [-V file format version] [-q quoted identifier]
  [-C code page specifier]  [-t field terminator]    [-r row terminator]
  [-i inputfile]            [-o outfile]             [-a packetsize]
  [-S server name]          [-U username]            [-P password]
  [-T trusted connection]   [-v version]             [-R regional enable]
  [-k keep null values]     [-E keep identity values]
  [-h "load hints"]         [-x generate xml format file]
  [-d database name]

bcpは列ヘッダーを出力できないことに注意してください。

参照: bcp Utility docs page。

上記ページの例:

bcp.exe MyTable out "D:\data.csv" -T -c -C 65001 -t , ...
59
John DaCosta

PowerShellを使用すると、Invoke-SqlcmdをExport-Csvにパイプすることで問題をきれいに解決できます。

#Requires -Module SqlServer
Invoke-Sqlcmd -Query "SELECT * FROM DimDate;" `
              -Database AdventureWorksDW2012 `
              -Server localhost |
Export-Csv -NoTypeInformation `
           -Path "DimDate.csv" `
           -Encoding UTF8

SQL Server 2016には、SqlServerモジュールが含まれています。このモジュールには、SSMS 2016をインストールしただけでも使用できるInvoke-Sqlcmdコマンドレットが含まれています。それ以前は、SQL Server 2012には古い SQLPSモジュール が含まれていました。これにより、モジュールが最初に使用されたときに現在のディレクトリがSQLSERVER:\に変更されます(その他のバグの中で)そのため、上記の#Requires行を次のように変更する必要があります:

Push-Location $PWD
Import-Module -Name SQLPS
# dummy query to catch initial surprise directory change
Invoke-Sqlcmd -Query "SELECT 1" `
              -Database  AdventureWorksDW2012 `
              -Server localhost |Out-Null
Pop-Location
# actual Invoke-Sqlcmd |Export-Csv pipeline

サンプルをSQL Server 2008および2008 R2に適合させるには、#Requires行を完全に削除し、標準のPowerShellホストの代わりに sqlps.exeユーティリティ を使用します。

Invoke-Sqlcmd は、sqlcmd.exeと同等のPowerShellです。テキストの代わりに System.Data.DataRow オブジェクトを出力します。

-Queryパラメーターは、sqlcmd.exeの-Qパラメーターと同様に機能します。エクスポートするデータを記述するSQLクエリを渡します。

-Databaseパラメーターは、sqlcmd.exeの-dパラメーターと同様に機能します。エクスポートするデータを含むデータベースの名前を渡します。

-Serverパラメーターは、sqlcmd.exeの-Sパラメーターと同様に機能します。エクスポートするデータを含むサーバーの名前を渡します。

Export-CSV は、汎用オブジェクトをCSVにシリアル化するPowerShellコマンドレットです。 PowerShellが付属しています。

-NoTypeInformationパラメーターは、CSV形式の一部ではない余分な出力を抑制します。既定では、コマンドレットは型情報を含むヘッダーを書き込みます。後でImport-Csvを使用してオブジェクトをデシリアライズするときにオブジェクトのタイプを知ることができますが、標準のCSVを期待するツールを混乱させます。

-Pathパラメーターは、sqlcmd.exeの-oパラメーターと同様に機能します。古いSQLPSモジュールを使用してスタックしている場合、この値の絶対パスが最も安全です。

-Encodingパラメーターは、sqlcmd.exeの-fまたは-uパラメーターと同様に機能します。デフォルトでは、Export-CsvはASCII文字のみを出力し、他のすべてを疑問符に置き換えます。代わりにUTF8を使用して、すべての文字を保持し、他のほとんどのツールとの互換性を維持します。

Sqlcmd.exeまたはbcp.exeに対するこのソリューションの主な利点は、有効なCSVを出力するためにコマンドをハッキングする必要がないことです。 Export-Csvコマンドレットがすべてを処理します。

主な欠点は、Invoke-Sqlcmdが結果セット全体を読み取ってからパイプラインに渡すことです。エクスポートする結果セット全体に十分なメモリがあることを確認してください。

何十億行もスムーズに動作しない場合があります。それが問題になる場合は、他のツールを試すか、 System.Data.SqlClient.SqlDataReader クラスを使用して、独自のInvoke-Sqlcmdの効率的なバージョンを実行できます。

これを実行したいが、列ヘッダーも持っている人のためのメモは、これが私がバッチファイルを使用した解決策です:

sqlcmd -S servername -U username -P password -d database -Q "set nocount on; set ansi_warnings off; sql query here;" -o output.tmp -s "," -W
type output.tmp | findstr /V \-\,\- > output.csv
del output.tmp

これにより、最初の結果(ヘッダーとデータ間の----、----セパレーターを含む)が一時ファイルに出力され、findstrでフィルター処理してその行が削除されます。 -,-を除外するため完全ではないことに注意してください。出力に列が1つしかない場合は機能せず、その文字列を含む正当な行も除外します。

11
Rudism

BCPの代替オプション:

exec master..xp_cmdshell 'BCP "sp_who" QUERYOUT C:\av\sp_who.txt -S MC0XENTC -T -c '
1
arnav

この答えは、@ iain-elderのソリューションに基づいています。これは、大規模なデータベースの場合を除いてうまく機能します(彼のソリューションで指摘されています)。テーブル全体がシステムのメモリに収まる必要がありますが、私にとってこれは選択肢ではありませんでした。 System.Data.SqlClient.SqlDataReader とカスタムCSVシリアライザー( 例についてはこちらを参照 )またはMS SQLドライバーを使用する別の言語を使用するのが最善のソリューションだと思いますCSVシリアル化。おそらく依存関係のないソリューションを探していた元の質問の精神で、以下のPowerShellコードがうまくいきました。特に、$ data配列をインスタンス化し、$ chunk_size行ごとに追加モードでExport-Csvを呼び出す場合、非常に遅く、非効率的です。

$chunk_size = 10000
$command = New-Object System.Data.SqlClient.SqlCommand
$command.CommandText = "SELECT * FROM <TABLENAME>"
$command.Connection = $connection
$connection.open()
$reader = $command.ExecuteReader()

$read = $TRUE
while($read){
    $counter=0
    $DataTable = New-Object System.Data.DataTable
    $first=$TRUE;
    try {
        while($read = $reader.Read()){

            $count = $reader.FieldCount
            if ($first){
                for($i=0; $i -lt $count; $i++){
                    $col = New-Object System.Data.DataColumn $reader.GetName($i)
                    $DataTable.Columns.Add($col)
                }
                $first=$FALSE;
            }

            # Better way to do this?
            $data=@()
            $emptyObj = New-Object System.Object
            for($i=1; $i -le $count; $i++){
                $data +=  $emptyObj
            }

            $reader.GetValues($data) | out-null
            $DataRow = $DataTable.NewRow()
            $DataRow.ItemArray = $data
            $DataTable.Rows.Add($DataRow)
            $counter += 1
            if ($counter -eq $chunk_size){
                break
            }
        }
        $DataTable | Export-Csv "output.csv" -NoTypeInformation -Append
    }catch{
        $ErrorMessage = $_.Exception.Message
        Write-Output $ErrorMessage
        $read=$FALSE
        $connection.Close()
        exit
    }
}
$connection.close()
0
jeffmax

次の2つの理由から、CMDで私のソリューションを実行する必要があります。

  1. クエリに二重引用符が含まれる場合があります
  2. リモートのSQL Serverインスタンスを照会するには、ログインユーザー名とパスワードが必要な場合があります

    sqlcmd -U [your_User]  -P[your_password] -S [your_remote_Server] -d [your_databasename]  -i "query.txt" -o "output.csv" -s"," -w 700
    
0
Mohsen Abasi

通常、sqlcmdには bcpユーティリティmssql-toolsの一部として)が付属しており、デフォルトでCSVにエクスポートされます。

使用法:

bcp {dbtable | query} {in | out | queryout | format} datafile

例えば:

bcp.exe MyTable out data.csv

すべてのテーブルを対応するCSVファイルにダンプするためのBashスクリプトを次に示します。

#!/usr/bin/env bash
# Script to dump all tables from SQL Server into CSV files via bcp.
# @file: bcp-dump.sh
server="sql.example.com" # Change this.
user="USER" # Change this.
pass="PASS" # Change this.
dbname="DBNAME" # Change this.
creds="-S '$server' -U '$user' -P '$pass' -d '$dbname'"
sqlcmd $creds -Q 'SELECT * FROM sysobjects sobjects' > objects.lst
sqlcmd $creds -Q 'SELECT * FROM information_schema.routines' > routines.lst
sqlcmd $creds -Q 'sp_tables' | tail -n +3 | head -n -2 > sp_tables.lst
sqlcmd $creds -Q 'SELECT name FROM sysobjects sobjects WHERE xtype = "U"' | tail -n +3 | head -n -2 > tables.lst

for table in $(<tables.lst); do
  sqlcmd $creds -Q "exec sp_columns $table" > $table.desc && \
  bcp $table out $table.csv -S $server -U $user -P $pass -d $dbname -c
done
0
kenorb

上記の答えは私にとってほとんど解決しましたが、解析されたCSVを正しく作成しません。

これが私のバージョンです。

sqlcmd -S myurl.com -d MyAzureDB -E -s, -W -i mytsql.sql | findstr /V /C:"-" /B > parsed_correctly.csv

sqlcmdは時代遅れだと言って、PowerShellの代替を支持する人は、sqlcmdがWindowsだけのものではないことを忘れています。私はLinuxを使用しています(Windowsの場合はPSを避けます)。

そうは言っても、bcpの方が簡単です。

0
Hack-R