Sqlcmd kullanarak SQL Server CSV formatında veri nasıl verilir?


136

Oldukça kolayca veri gibi bir metin dosyasına dökümü:

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

Ancak, yardım dosyalarına baktım, SQLCMDancak özellikle CSV için bir seçenek görmedim.

Verileri kullanarak tablodan CSV metin dosyasına dökmenin bir yolu var mı SQLCMD?


Bunun sqlcmd yoluyla olması gerekir veya aşağıdaki gibi başka bir program kullanabilirsiniz: codeproject.com/KB/aspnet/ImportExportCSV.aspx
Bernhard Hofmann

Olmak zorunda değilim ama sqlcmd'nin başka bir ihracat aracına dalmadan önce bunu gerçekten yapıp yapamayacağını bilmek istedim. Belirtilmesi gereken bir şey, yazılabilir olması gerektiğidir.
Ray

Tablolarınızdan CSV çıktısını, maddelere göre nerede ve siparişe göre özelleştirilebilen bir SSMS 2008 eklenti aracı vardır. store.nmally.com/software/sql-server-management-studio-addons/…

Yanıtlar:


140

Bunun gibi bir şey çalıştırabilirsiniz:

sqlcmd -S MyServer -d myDB -E -Q "select col1, col2, col3 from SomeTable" 
       -o "MyData.csv" -h-1 -s"," -w 700
  • -h-1 sütun adı üstbilgilerini sonuçtan kaldırır
  • -s"," sütun ayırıcıyı,
  • -w 700 satır genişliğini 700 karakter olarak ayarlar (bunun en uzun satır kadar geniş olması gerekir veya bir sonraki satıra sarılır)

22
Bu şekilde yapılan uyarı, verilerinizde virgül bulunmayabileceğidir.
Sarel Botha

1
@SarelBotha, bu sorunun üstesinden gelebilir, '""' + col1 + '""' AS col1çift ​​tırnak içine alınmış (iki katına çıkmış ) veya sadece saklı bir prosedür çağırabilirsiniz.
MisterIsaak

2
@JIsaak Sonra verilerinizde çift tırnak olmadığından emin olun veya çift tırnaklarınızı iki çift tırnak ile değiştirdiğinizden emin olun.
Sarel Botha

1
Birisi verinin içindeki virgüllere izin vermek için ne yapılması gerektiğini açıklayabilir mi? Her sütunu '""' + ___ + '""' ile çevremiz mi gerekiyor?
Ahmed

2
Bu cevap şimdi güncel değil. PowerShell komut dosyaları daha esnektir ve SQL Server'da Job Agent olarak çalıştırılabilir.
Clinton Ward

75

PowerShell ile sorunu Invoke-Sqlcmd'yi Export-Csv'ye bağlayarak düzgün bir şekilde çözebilirsiniz.

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

SQL Server 2016, yalnızca SSMS 2016 yükleseniz bile sahip olacağınız cmdlet'i içeren SqlServer modülünü içerir Invoke-Sqlcmd. Bundan önce, SQL Server 2012 , geçerli dizini modülün olduğu zamana değiştirecek eski SQLPS modülünü içermiştir.SQLSERVER:\ ilk o, değiştirmek gerekir için çok (diğer böcek arasında) kullanılan #Requiresyukarıdaki satırı:

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

Örneği SQL Server 2008 ve 2008 R2 için uyarlamak için, #Requiressatırı tamamen kaldırın ve standart PowerShell ana bilgisayarı yerine sqlps.exe yardımcı programını kullanın.

Invoke-Sqlcmd , sqlcmd.exe'nin PowerShell eşdeğeridir. Metin yerine System.Data.DataRow nesnelerini çıktılar .

-QueryParametre gibi çalışır -QsqlCmd.exe parametresi. Dışa aktarmak istediğiniz verileri açıklayan bir SQL sorgusu iletin.

-DatabaseParametre gibi çalışır -dsqlCmd.exe parametresi. Dışa aktarılacak verileri içeren veritabanının adını iletin.

-ServerParametre gibi çalışır -SsqlCmd.exe parametresi. Dışa aktarılacak verileri içeren sunucunun adını iletin.

Export-CSV , genel nesneleri CSV'ye serileştiren bir PowerShell cmdletidir. PowerShell ile birlikte gönderilir.

-NoTypeInformationParametre CSV formatında bir parçası olmayan ekstra çıkış bastırır. Varsayılan olarak cmdlet, tür bilgisi içeren bir başlık yazar. Nesnenin türünü daha sonra serisini kaldırmak istediğinizde bilmenizi sağlar Import-Csv, ancak standart CSV'yi bekleyen araçları karıştırır.

-PathParametre gibi çalışır -osqlCmd.exe parametresi. Eski SQLPS modülünü kullanarak sıkışıp kalırsanız, bu değer için tam bir yol en güvenlidir .

-EncodingParametresi gibi çalışır -fveya -usqlCmd.exe parametreleri. Varsayılan olarak Export-Csv yalnızca ASCII karakterleri verir ve diğerlerini soru işaretleriyle değiştirir. Tüm karakterleri korumak ve diğer birçok araçla uyumlu kalmak için UTF8 kullanın.

Bu çözümün sqlcmd.exe veya bcp.exe'ye göre ana avantajı, geçerli CSV çıktısı almak için komutu kesmek zorunda olmamanızdır. Export-Csv cmdlet hepsini sizin için halleder.

Ana dezavantaj, Invoke-Sqlcmdboru hattı boyunca geçmeden önce tüm sonuç setini okumasıdır. Dışa aktarmak istediğiniz sonuç kümesi için yeterli belleğe sahip olduğunuzdan emin olun.

Milyarlarca satır için düzgün çalışmayabilir. Bu bir sorunsa, diğer araçları deneyebilir veya System.Data.SqlClient.SqlDataReader sınıfını Invoke-Sqlcmdkullanarak kendi etkin sürümünüzü kullanabilirsiniz .


5
Diğer cevaplar dürüstçe emmek, doğru yapmanın tek yolu bu. Keşke daha açık olsaydı.
Shagglez

1
SQL 2008 R2, Invoke-Sqlcmd kullanmak için "sqlps.exe" aracını çalıştırmak zorunda kaldı. Görünüşe göre Import-Module kullanmak için SQL 2012 gerekir? Yine de "sqlps.exe" içinde çalışır - ayrıntılar için bu konuya bakın .
Mister_Tom

1
@Mister_Tom iyi bir nokta. SQLPS modülü, SQL 2012 ile birlikte tanıtıldı. Bu sorunun cevabı şimdi eski sürümlere nasıl uyarlanacağını açıklıyor.
Iain Samuel McLean Elder

1
@JasonMatney PowerShell, Windows sistemleri için yeni yönetim arabirimidir, ancak standart hale gelmeden önce birçok SQL Server tavsiyesi yayınlanmıştır. Kelimeyi yay! :-)
Iain Samuel McLean Elder

1
Bu yanıt, yararlı bilgiler ve sorunu ele almak için güçlü ve esnek bir ALTERNATİF yol sağlar, ancak orijinal soruyu özellikle sorulduğu gibi cevaplamak tamamen başarısız olur . Ben de bir powershell hayranıyım, ama evangelizmin histeriye dönüşmesine izin vermeyelim. SQLCMD çok yakında yok olmayacak.
barbekü

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

Son satır CSV'ye özgü seçenekleri içerir.

  • -W   her bir alandan sonraki boşlukları kaldırın
  • -s","   sütun ayırıcıyı virgül (,) olarak ayarlar
  • -w 999   satır genişliğini 999 karakter olarak ayarlar

scottm'ın cevabı kullandığım şeye çok yakın, ama -Wgerçekten güzel bir ek olarak görüyorum: Başka bir yerde CSV kullandığımda boşluk kesmem gerekmiyor.

Ayrıca MSDN sqlcmd referansına bakın . O koyar /?utanç seçeneğin çıktı.


19
@sims sorgusunun / giriş dosyasının başında "nocount on" yazdı
d -_- b

7
Üstbilgilerin altını nasıl kaldırabilirim?
ntombela

@gugulethun: Sütun adını ilk satıra koymak için sorgunuzda birleşme yapabilirsiniz.
Nordes

2
Bu bir cazibe gibi çalışır, ancak sütun ayırıcı içeriyorsa bozuk bir csv dosyası alıyorum ...
Peter

Bu yorumu kabul edilen cevaba da ekledim ama ... bu sorunu çözebilir '""' + col1 + '""' AS col1, çift tırnak içine alabilir (iki katına çıkarabilir ) veya sadece saklı bir prosedürü çağırabilirsiniz.
MisterIsaak

59

Bu bcpamaçlanmamış mı?

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

Sözdizimini kontrol etmek için bunu komut satırınızdan çalıştırın.

bcp /?

Örneğin:

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]

Lütfen bcpsütun başlıklarını çıktılayamayacağınızı unutmayın .

Bkz . Bcp Yardımcı Program dokümanları sayfası.

Yukarıdaki sayfadan örnek:

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

1
ServerName = BilgisayarınızınAdı \ SQLServerName, ancak o zaman başka bir hatayı çalıştırır
Hammad Khan

1
: Eğer bcp.exe için tüm belgeleri görmek istiyorum technet.microsoft.com/en-us/library/ms162802.aspx
Robert Bernstein

5
Sütun adlarını da başlık olarak dışa aktarmanız gerekirse ne yaparsınız? Bcp kullanan basit bir genel çözüm var mı?
Iain Samuel McLean Elder

@johndacosta çok teşekkürler. Sütun başlıklarını da nasıl basardınız? Hiçbir yerde kolay bir geçiş görmüyorum. Teşekkürler!
Rachael

1
bcpüstbilgi (sütun adları) içermez, ancak sqlcmddeneyimimden ~ 10 kat daha hızlıdır . Gerçekten büyük bir veri bcpiçin, verileri almak için kullanabilirsiniz sqlcmdve başlığı almak için (üst 0 * 'yı seçin ...) kullanın ve sonra bunları birleştirin.
YJZ

12

Bunu yapmak isteyen ancak sütun başlıklarına sahip herkes için bir not, bu bir toplu iş dosyası kullandığım çözüm:

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

Bu, başlangıç ​​sonuçlarını (üstbilgiler ve veriler arasındaki ----, ---- ayırıcıları dahil) geçici bir dosyaya çıkarır ve sonra bu satırı findstr. Filtrelediği için mükemmel olmadığını unutmayın; -,-çıktıda yalnızca bir sütun varsa işe yaramaz ve bu dizeyi içeren meşru satırları da filtreler.


1
Bunun yerine şu filtreyi kullanın: findstr / r / v ^ \ - [, \ -] * $> output.csv Nedense simle ^ [, \ -] * $ tüm satırlarla eşleşir.
Vladimir Korolev

3
Her zaman ^ ile çift tırnak içine bir normal ifade koyun veya garip sonuçlar elde edersiniz, çünkü ^ cmd.exe için bir kaçış karakteri. Yukarıdaki her iki normal ifade de söyleyebildiğim kadarıyla düzgün çalışmıyor, ancak bu şu şekilde çalışıyor: findstr / r / v "^ - [-,] * -. $" (İle testten önce $ yankı, ancak sqlcmd çıkışı için olmayabilir)
JimG

Tarih ve saat arasında bir yerine 2 boşluk bulunan tarihlerle ilgili bir sorun da vardır. CSV'yi Excel'de açmaya çalıştığınızda 00: 00.0 olarak gösterilir. Bunu çözmenin kolay bir yolu, tüm "" "yerinde" "SED kullanarak yerinde aramak ve değiştirmek olacaktır. Betiğinize ekleme komutu şöyledir: SED -i "s / / / g" output.csv. SED hakkında daha fazla bilgi gnuwin32.sourceforge.net/packages/sed.htm
PollusB

bu doğru cevap, @ JimG'nin eklenmesiyle mükemmel çalışıyor. Ayırıcı için noktalı virgül ve giriş için bir sql dosyası kullandım, dosya sayılmayan açık ve ansi_warning kapalı parçayı ve boşluk kaldırma için -W anahtarını içeriyordu
robotik

1

Bu cevap @ iain-elder'un çözümüne dayanmaktadır. Bu çözüm büyük veritabanı durumu (çözümünde belirtildiği gibi) dışında iyi sonuç verir. Tüm tablonun sisteminizin belleğine sığması gerekiyor ve benim için bu bir seçenek değildi. En iyi çözüm System.Data.SqlClient.SqlDataReader ve özel bir CSV serileştirici ( bir örnek için buraya bakın ) veya MS SQL sürücüsü ve CSV serileştirme ile başka bir dil kullanacağından şüpheleniyorum . Muhtemelen bağımlılık çözümü olmayan orijinal sorunun ruhuna göre, aşağıdaki PowerShell kodu benim için çalıştı. Özellikle $ data dizisini somutlaştırırken ve her $ chunk_size satırı için ekleme modunda Export-Csv'yi çağırırken çok yavaş ve verimsizdir.

$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()

1

BCP ile alternatif seçenek:

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

1

Genellikle varsayılan olarak CSV'ye dışa aktarılan yardımcı programla (bir parçası olarak ) sqlcmdgelir .bcpmssql-tools

Kullanımı:

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

Örneğin:

bcp.exe MyTable out data.csv

Tüm tabloları karşılık gelen CSV dosyalarına dökmek için Bash betiği aşağıdadır :

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

Yukarıdaki bir cevap neredeyse benim için çözdü, ancak doğru bir şekilde ayrıştırılmış bir CSV oluşturmuyor.

İşte benim versiyonum:

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

sqlcmdBazı PowerShell alternatifi lehine eski olduğunu söyleyen biri sqlcmd, sadece Windows için değil unutuyor . Linux'tayım (ve Windows'ta PS'den yine de kaçınırım).

Bütün bunları söyledikten sonra bcpdaha kolay buluyorum .


0

Aşağıdaki 2 nedenden bu yana, çözümümü CMD'de çalıştırmalısınız:

  1. Sorguda çift tırnak işareti olabilir
  2. Oturum açma kullanıcı adı ve parolası bazen uzak bir SQL Server örneğini sorgulamak için gereklidir

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

-2

Bunu hackish bir şekilde yapabilirsiniz. Kesmek kullanırken dikkatli olun sqlcmd. Veride çift tırnak işareti veya virgül varsa sorun yaşarsınız.

Basit bir komut dosyasını düzgün şekilde yapmak için kullanabilirsiniz:

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 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!")

Kaynak: VBScript ile CSV'ye SQL çıkışı yazma .


1
Downvote için bir açıklama iyi olurdu. Cevabım doğru: Bunu sqlcmd ile yapamazsınız. Ayrıca görevi yerine getirmenin alternatif bir yolunu sundum.
Sarel Botha

4
Aşağı oy, OP'nin sqlcmd ile sorduğu şeyi açıkça yapabilmenizdir.
Brian Driscoll

2
@BrianDriscoll, O bir demedim olamaz ile bunu sqlcmd, sadece gerçeği belirten edildi sqlcmdve böylece herhangi biri için ancak kullanışlı olma, düzgün virgül kaçan değil ciddi CSV çıkışı.
Sebastian

Bunu söyledim, ama aşağı oylardan bıktım, bu yüzden cevabımı düzenledim. Düzenlememi daha doğru yapacağım.
Sarel Botha
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.