Question

Je peux facilement transférer des données dans un fichier texte tel que:

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

Cependant, j’ai consulté les fichiers d’aide de SQLCMD mais je n’ai pas vu d’option spécifique pour CSV.

Y a-t-il un moyen de vider les données d'une table dans un fichier texte CSV en utilisant SQLCMD ?

Était-ce utile?

La solution

Vous pouvez exécuter quelque chose comme ceci:

sqlcmd -S MyServer -d myDB -E -Q "select col1, col2, col3 from SomeTable" 
       -o "MyData.csv" -h-1 -s"," -w 700
  • -h-1 supprime les en-têtes de noms de colonnes du résultat
  • -s "," "définit le séparateur de colonnes sur,
  • -w 700 définit la largeur de la ligne sur 700 caractères (elle devra être aussi large que la ligne la plus longue ou être renvoyée à la ligne suivante)

Autres conseils

sqlcmd -S myServer -d myDB -E -o "MyData.txt" ^
    -Q "select bar from foo" ^
    -W -w 999 -s","

La dernière ligne contient des options spécifiques à CSV.

  • -W & nbsp; supprimer les espaces de fin de chaque champ individuel
  • -s ", " & nbsp; définit le séparateur de colonne sur la virgule (,)
  • -w 999 & nbsp; définit la largeur de la ligne sur 999 caractères

scottm's answer est très proche de ce que j'utilise, mais je trouve le -W très intéressant: je n'ai pas besoin de rogner les espaces lorsque je consomme le CSV ailleurs.

Voir également la référence MSDN sqlcmd . Cela fait honte à la sortie de l'option /? .

N'est-ce pas que bcp était destiné?

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

Exécutez ceci à partir de votre ligne de commande pour vérifier la syntaxe.

bcp /?

Par exemple:

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]

Notez que bcp ne peut pas générer les en-têtes de colonne.

Voir: Utilitaire bcp dans la page "Documents".

Exemple de la page ci-dessus:

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

Avec PowerShell, vous pouvez résoudre le problème en connectant 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 inclut le module SqlServer , qui contient la cmdlet Invoke-Sqlcmd , que vous aurez même si vous installez simplement SSMS 2016. Avant cela, SQL Server 2012 incluait l'ancien module SQLPS . >, qui changerait le répertoire actuel en SQLSERVER: \ lors de la première utilisation du module (entre autres bogues), vous devrez donc changer le #Requires ligne ci-dessus à:

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

Pour adapter l'exemple à SQL Server 2008 et 2008 R2, supprimez entièrement la ligne #Requires et utilisez la utilitaire sqlps.exe à la place de l'hôte PowerShell standard.

Invoke-Sqlcmd est l'équivalent PowerShell de sqlcmd.exe. . Au lieu de texte, le résultat est System.Data.DataRow . objets.

Le paramètre -Query fonctionne comme le paramètre -Q de sqlcmd.exe. Transmettez-lui une requête SQL décrivant les données à exporter.

Le paramètre -Database fonctionne comme le paramètre -d de sqlcmd.exe. Donnez-lui le nom de la base de données contenant les données à exporter.

Le paramètre -Server fonctionne comme le paramètre -S de sqlcmd.exe. Donnez-lui le nom du serveur contenant les données à exporter.

Export-CSV est une applet de commande PowerShell qui sérialise des objets génériques. au format CSV. Il est livré avec PowerShell.

Le paramètre -NoTypeInformation supprime les sorties supplémentaires qui ne font pas partie du format CSV. Par défaut, la cmdlet écrit un en-tête avec les informations de type. Il vous permet de connaître le type de l'objet lorsque vous le désérialisez ultérieurement avec Import-Csv , mais cela confond les outils qui attendent un format CSV standard.

Le paramètre -Path fonctionne comme le paramètre -o de sqlcmd.exe. Un chemin complet pour cette valeur est le plus sûr si vous êtes bloqué avec l'ancien module SQLPS .

Le paramètre -Encoding fonctionne comme les paramètres -f ou -u de sqlcmd.exe. Par défaut, Export-Csv génère uniquement des caractères ASCII et remplace tous les autres par des points d'interrogation. Utilisez plutôt UTF8 pour conserver tous les caractères et rester compatible avec la plupart des autres outils.

Le principal avantage de cette solution par rapport à sqlcmd.exe ou à bcp.exe est que vous n'avez pas à pirater la commande pour générer un fichier CSV valide. La cmdlet Export-Csv gère tout cela pour vous.

Le principal inconvénient est que Invoke-Sqlcmd lit l'intégralité du jeu de résultats avant de le transmettre le long du pipeline. Assurez-vous de disposer de suffisamment de mémoire pour tout le jeu de résultats à exporter.

Cela risque de ne pas fonctionner correctement pour des milliards de lignes. Si cela pose un problème, vous pouvez essayer les autres outils ou lancer votre propre version efficace de Invoke-Sqlcmd en utilisant Classe System.Data.SqlClient.SqlDataReader .

Une note pour ceux qui souhaitent faire cela mais qui ont aussi les en-têtes de colonne, voici la solution pour laquelle j'ai utilisé un fichier de commandes:

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

Ceci affiche les résultats initiaux (y compris les séparateurs ----, ---- entre les en-têtes et les données) dans un fichier temporaire, puis supprime cette ligne en la filtrant via findstr. Notez que ce n'est pas parfait car il filtre -, - - il ne fonctionnera pas s'il n'y a qu'une seule colonne dans la sortie et il filtrera également les lignes légitimes contenant cette chaîne.

Autre option avec BCP:

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

Cette réponse s'appuie sur la solution de @ iain-elder, qui fonctionne bien à l'exception du cas de la base de données volumineuse (comme indiqué dans sa solution). La table entière doit tenir dans la mémoire de votre système, et pour moi, ce n'était pas une option. Je pense que la meilleure solution utiliserait le System.Data. SqlClient.SqlDataReader et un sérialiseur CSV personnalisé ( voir ici pour un exemple ) ou une autre langue avec un MS Pilote SQL et sérialisation CSV. Dans l'esprit de la question initiale qui cherchait probablement une solution sans dépendance, le code PowerShell ci-dessous fonctionnait pour moi. Il est très lent et inefficace, en particulier pour instancier le tableau $ data et appeler Export-Csv en mode ajout pour chaque ligne $ chunk_size.

$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 = 

Cette réponse s'appuie sur la solution de @ iain-elder, qui fonctionne bien à l'exception du cas de la base de données volumineuse (comme indiqué dans sa solution). La table entière doit tenir dans la mémoire de votre système, et pour moi, ce n'était pas une option. Je pense que la meilleure solution utiliserait le System.Data. SqlClient.SqlDataReader et un sérialiseur CSV personnalisé ( voir ici pour un exemple ) ou une autre langue avec un MS Pilote SQL et sérialisation CSV. Dans l'esprit de la question initiale qui cherchait probablement une solution sans dépendance, le code PowerShell ci-dessous fonctionnait pour moi. Il est très lent et inefficace, en particulier pour instancier le tableau $ data et appeler Export-Csv en mode ajout pour chaque ligne $ chunk_size.

<*>.Exception.Message Write-Output $ErrorMessage $read=$FALSE $connection.Close() exit } } $connection.close()

Généralement, sqlcmd est fourni avec Utilitaire> bcp (faisant partie de mssql-tools ), qui exporte par défaut vers le format CSV.

Utilisation:

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

Par exemple:

bcp.exe MyTable out data.csv

Pour vider toutes les tables dans les fichiers CSV correspondants, voici le script 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

Une réponse ci-dessus a presque résolu le problème pour moi, mais cela ne crée pas correctement un fichier CSV analysé.

Voici ma version:

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

Quelqu'un qui dit que sqlcmd est obsolète au profit d'une alternative à PowerShell, oublie que sqlcmd ne concerne pas que Windows. Je suis sous Linux (et sous Windows, j’évite malgré tout PS).

Cela dit, je trouve bcp plus facile.

Depuis les 2 raisons suivantes, vous devez exécuter ma solution dans CMD:

  1. Il peut y avoir des guillemets doubles dans la requête
  2. Nom d'utilisateur de connexion & amp; un mot de passe est parfois nécessaire pour interroger une instance SQL Server distante

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

Vous pouvez le faire de manière furtive. Faites attention en utilisant le hack sqlcmd . Si les données comportent des guillemets ou des virgules, vous rencontrerez des problèmes.

Vous pouvez utiliser un script simple pour le faire correctement:

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Data Exporter                                                 '
'                                                               '
' Description: Allows the output of data to CSV file from a SQL '
'       statement to either Oracle, SQL Server, or MySQL        '
' Author: C. Peter Chen, http://dev-notes.com                   '
' Version Tracker:                                              '
'       1.0   20080414 Original version                         '
'   1.1   20080807 Added email functionality                '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
option explicit
dim dbType, dbHost, dbName, dbUser, dbPass, outputFile, email, subj, body, smtp, smtpPort, sqlstr

'''''''''''''''''
' Configuration '
'''''''''''''''''
dbType = "oracle"                 ' Valid values: "oracle", "sqlserver", "mysql"
dbHost = "dbhost"                 ' Hostname of the database server
dbName = "dbname"                 ' Name of the database/SID
dbUser = "username"               ' Name of the user
dbPass = "password"               ' Password of the above-named user
outputFile = "c:\output.csv"      ' Path and file name of the output CSV file
email = "email@me.here"           ' Enter email here should you wish to email the CSV file (as attachment); if no email, leave it as empty string ""
  subj = "Email Subject"          ' The subject of your email; required only if you send the CSV over email
  body = "Put a message here!"    ' The body of your email; required only if you send the CSV over email
  smtp = "mail.server.com"        ' Name of your SMTP server; required only if you send the CSV over email
  smtpPort = 25                   ' SMTP port used by your server, usually 25; required only if you send the CSV over email
sqlStr = "select user from dual"  ' SQL statement you wish to execute
'''''''''''''''''''''
' End Configuration '
'''''''''''''''''''''



dim fso, conn

'Create filesystem object 
set fso = CreateObject("Scripting.FileSystemObject")

'Database connection info
set Conn = CreateObject("ADODB.connection")
Conn.ConnectionTimeout = 30
Conn.CommandTimeout = 30
if dbType = "oracle" then
    conn.open("Provider=MSDAORA.1;User ID=" & dbUser & ";Password=" & dbPass & ";Data Source=" & dbName & ";Persist Security Info=False")
elseif dbType = "sqlserver" then
    conn.open("Driver={SQL Server};Server=" & dbHost & ";Database=" & dbName & ";Uid=" & dbUser & ";Pwd=" & dbPass & ";")
elseif dbType = "mysql" then
    conn.open("DRIVER={MySQL ODBC 3.51 Driver}; SERVER=" & dbHost & ";PORT=3306;DATABASE=" & dbName & "; UID=" & dbUser & "; PASSWORD=" & dbPass & "; OPTION=3")
end if

' Subprocedure to generate data.  Two parameters:
'   1. fPath=where to create the file
'   2. sqlstr=the database query
sub MakeDataFile(fPath, sqlstr)
    dim a, showList, intcount
    set a = fso.createtextfile(fPath)

    set showList = conn.execute(sqlstr)
    for intcount = 0 to showList.fields.count -1
        if intcount <> showList.fields.count-1 then
            a.write """" & showList.fields(intcount).name & ""","
        else
            a.write """" & showList.fields(intcount).name & """"
        end if
    next
    a.writeline ""

    do while not showList.eof
        for intcount = 0 to showList.fields.count - 1
            if intcount <> showList.fields.count - 1 then
                a.write """" & showList.fields(intcount).value & ""","
            else
                a.write """" & showList.fields(intcount).value & """"
            end if
        next
        a.writeline ""
        showList.movenext
    loop
    showList.close
    set showList = nothing

    set a = nothing
end sub

' Call the subprocedure
call MakeDataFile(outputFile,sqlstr)

' Close
set fso = nothing
conn.close
set conn = nothing

if email <> "" then
    dim objMessage
    Set objMessage = CreateObject("CDO.Message")
    objMessage.Subject = "Test Email from vbs"
    objMessage.From = email
    objMessage.To = email
    objMessage.TextBody = "Please see attached file."
    objMessage.AddAttachment outputFile

    objMessage.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
    objMessage.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = smtp
    objMessage.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = smtpPort

objMessage.Configuration.Fields.Update

    objMessage.Send
end if

'You're all done!!  Enjoy the file created.
msgbox("Data Writer Done!")

Source: Écriture de la sortie SQL au format CSV avec VBScript .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top