it-swarm.com.de

Wie exportiere ich Daten als CSV-Format von SQL Server mit sqlcmd?

Ich kann Daten ganz einfach in eine Textdatei ausgeben:

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

Ich habe mir jedoch die Hilfedateien für SQLCMD angesehen, aber keine Option speziell für CSV gefunden. 

Gibt es eine Möglichkeit, Daten aus einer Tabelle mit SQLCMD in eine CSV-Textdatei zu kopieren?

112
Ray Vega

Sie können so etwas ausführen:

sqlcmd -S MyServer -d myDB -E -Q "select col1, col2, col3 from SomeTable" 
       -o "MyData.csv" -h-1 -s"," -w 700
  • -h-1 entfernt Spaltennamen aus dem Ergebnis
  • -s"," setzt den Spaltentrenner auf 
  • -w 700 setzt die Zeilenbreite auf 700 Zeichen (diese muss so breit sein wie die längste Zeile oder sie wird zur nächsten Zeile umgebrochen)
117
scottm
sqlcmd -S myServer -d myDB -E -o "MyData.txt" ^
    -Q "select bar from foo" ^
    -W -w 999 -s","

Die letzte Zeile enthält CSV-spezifische Optionen.

  • -W entferne Leerzeichen aus jedem einzelnen Feld
  • -s"," setzt den Spaltentrenner auf das Komma (,) 
  • -w 999 setzt die Zeilenbreite auf 999 Zeichen

scottms Antwort ist sehr nahe an dem, was ich verwende, aber ich finde, dass der -W eine wirklich schöne Ergänzung ist: Ich muss den Leerraum nicht kürzen, wenn ich die CSV anderswo konsumiere.

Siehe auch die MSDN-sqlcmd-Referenz . Die Ausgabe der Option /? wird beschämt.

62
ESV

Ist das nicht bcp gedacht?

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

Führen Sie dies über Ihre Befehlszeile aus, um die Syntax zu überprüfen.

bcp /?

Zum Beispiel:

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]

Bitte beachten Sie, dass bcp keine Spaltenköpfe ausgeben kann.

Siehe: bcp Utility docs-Seite.

Beispiel von der obigen Seite:

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

Mit PowerShell können Sie das Problem problemlos lösen, indem Sie Invoke-Sqlcmd in Export-Csv leiten.

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

SQL Server 2016 enthält das Modul SqlServer, das das Invoke-Sqlcmd-Cmdlet enthält, das Sie auch dann haben, wenn Sie SSMS 2016 installieren. Zuvor enthielt SQL Server 2012 die alten SQLPS. module , wodurch das aktuelle Verzeichnis bei der ersten Verwendung des Moduls in SQLSERVER:\ geändert wurde (unter anderen Fehlern). Daher müssen Sie die #Requires-Zeile oben wie folgt ändern:

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

Entfernen Sie zur Anpassung des Beispiels für SQL Server 2008 und 2008 R2 die Zeile #Requires vollständig und verwenden Sie das Dienstprogramm sqlps.exe anstelle des Standard-PowerShell-Hosts.

Invoke-Sqlcmd ist das PowerShell-Äquivalent von sqlcmd.exe. Anstelle von Text werden System.Data.DataRow Objekte ausgegeben.

Der -Query-Parameter funktioniert wie der -Q-Parameter von sqlcmd.exe. Übergeben Sie eine SQL-Abfrage, die die Daten beschreibt, die Sie exportieren möchten.

Der -Database-Parameter funktioniert wie der -d-Parameter von sqlcmd.exe. Übergeben Sie den Namen der Datenbank, die die zu exportierenden Daten enthält.

Der -Server-Parameter funktioniert wie der -S-Parameter von sqlcmd.exe. Übergeben Sie den Namen des Servers, der die zu exportierenden Daten enthält.

Export-CSV ist ein PowerShell-Cmdlet, das generische Objekte in CSV serialisiert. Es wird mit PowerShell geliefert.

Der -NoTypeInformation-Parameter unterdrückt zusätzliche Ausgaben, die nicht zum CSV-Format gehören. Standardmäßig schreibt das Cmdlet einen Header mit Typinformationen. Sie können den Typ des Objekts erkennen, wenn Sie es später mit Import-Csv deserialisieren, aber es verwirrt Tools, die Standard-CSV erwarten.

Der -Path-Parameter funktioniert wie der -o-Parameter von sqlcmd.exe. Ein vollständiger Pfad für diesen Wert ist am sichersten, wenn Sie das alte SQLPS -Modul verwenden.

Der -Encoding-Parameter funktioniert wie die -f- oder -u-Parameter von sqlcmd.exe. Standardmäßig gibt Export-Csv nur ASCII Zeichen aus und ersetzt alle anderen Zeichen mit Fragezeichen. Verwenden Sie stattdessen UTF8, um alle Zeichen zu erhalten und mit den meisten anderen Tools kompatibel zu bleiben.

Der Hauptvorteil dieser Lösung gegenüber sqlcmd.exe oder bcp.exe besteht darin, dass Sie den Befehl nicht hacken müssen, um gültige CSV-Werte auszugeben. Das Export-Csv-Cmdlet übernimmt alles für Sie.

Der Hauptnachteil ist, dass Invoke-Sqlcmd die gesamte Ergebnismenge liest, bevor sie an der Pipeline übergeben wird. Stellen Sie sicher, dass Sie über genügend Speicher für die gesamte Ergebnismenge verfügen, die Sie exportieren möchten.

Bei Milliarden von Zeilen funktioniert es möglicherweise nicht reibungslos. Wenn dies ein Problem ist, können Sie die anderen Tools ausprobieren oder Ihre eigene effiziente Version von Invoke-Sqlcmd mit System.Data.SqlClient.SqlDataReader class rollen.

Ein Hinweis für alle, die dies tun möchten, aber auch über die Spaltenüberschriften verfügen. Dies ist die Lösung, bei der ich eine Batchdatei verwendet habe:

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

Dies gibt die ersten Ergebnisse (einschließlich der Trennzeichen ----, ---- zwischen den Kopfzeilen und den Daten) in eine temporäre Datei aus und entfernt dann diese Zeile, indem sie durch findstr herausgefiltert wird. Beachten Sie, dass es nicht perfekt ist, da es -,- herausfiltert. Es funktioniert nicht, wenn nur eine Spalte in der Ausgabe enthalten ist. Außerdem werden legitime Zeilen mit dieser Zeichenfolge herausgefiltert.

10
Rudism

Alternative Option mit BCP:

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

Diese Antwort baut auf der Lösung von @ iain-elder auf, die abgesehen von dem Fall großer Datenbanken (wie in seiner Lösung dargelegt) gut funktioniert. Die gesamte Tabelle muss in den Speicher Ihres Systems passen, und für mich war dies keine Option. Ich vermute, die beste Lösung würde den System.Data.SqlClient.SqlDataReader und einen benutzerdefinierten CSV-Serialisierer ( siehe hier ) oder eine andere Sprache mit einem MS SQL-Treiber und CSV-Serialisierung verwenden. Im Sinne der ursprünglichen Frage, die wahrscheinlich nach einer Lösung ohne Abhängigkeit suchte, funktionierte der folgende PowerShell-Code für mich. Es ist sehr langsam und ineffizient, insbesondere beim Instantiieren des $ data-Arrays und beim Aufruf von Export-Csv im Anfügemodus für jede $ chunk_size-Zeile. 

$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?
            [email protected]()
            $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

Aus folgenden zwei Gründen sollten Sie meine Lösung in CMD ausführen:

  1. Die Abfrage kann doppelte Anführungszeichen enthalten
  2. Benutzername und Kennwort für die Anmeldung sind manchmal erforderlich, um eine Remote-SQL Server-Instanz abzufragen

    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

Normalerweise enthält sqlcmd das Dienstprogramm bcp (als Teil von mssql-tools), das standardmäßig in CSV exportiert wird.

Verwendungszweck:

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

Zum Beispiel:

bcp.exe MyTable out data.csv

Um alle Tabellen in entsprechende CSV-Dateien zu kopieren, ist hier das Bash -Skript:

#!/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

Eine Antwort oben hat es fast für mich gelöst, aber es wird nicht korrekt eine geparste CSV erstellt. 

Hier ist meine Version:

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

Wer sagt, dass sqlcmd zugunsten einiger PowerShell-Alternativen veraltet ist, vergisst, dass sqlcmd nicht nur für Windows gilt. Ich bin unter Linux (und unter Windows vermeide ich sowieso PS).

Nach all dem finde ich bcp einfacher.

0
Hack-R