提问人:Ray 提问时间:1/9/2009 最后编辑:SteveCRay 更新时间:3/24/2022 访问量:502804
如何使用sqlcmd从SQL Server将数据导出为CSV格式?
How to export data as CSV format from SQL Server using sqlcmd?
问:
我可以很容易地将数据转储到文本文件中,例如:
sqlcmd -S myServer -d myDB -E -Q "select col1, col2, col3 from SomeTable"
-o "MyData.txt"
但是,我已经查看了帮助文件,但没有看到专门针对 CSV 的选项。SQLCMD
有没有办法使用表将数据转储到 CSV 文本文件中?SQLCMD
答:
你可以用一种黑客的方式做到这一点。小心使用黑客。如果数据有双引号或逗号,您将遇到麻烦。sqlcmd
您可以使用一个简单的脚本来正确执行此操作:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 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 protected]" ' 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!")
来源:使用 VBScript 将 SQL 输出写入 CSV。
评论
sqlcmd
sqlcmd
你可以运行如下操作:
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 个字符(这需要与最长行一样宽,否则它将换行到下一行)
评论
'""' + col1 + '""' AS col1
sqlcmd -S myServer -d myDB -E -o "MyData.txt" ^
-Q "select bar from foo" ^
-W -w 999 -s","
最后一行包含特定于 CSV 的选项。
-W
从每个单独的字段中删除尾随空格-s","
将列分隔符设置为逗号 (,)-w 999
将行宽设置为 999 个字符
scottm 的答案与我使用的答案非常接近,但我发现这是一个非常好的补充:当我在其他地方使用 CSV 时,我不需要修剪空格。-W
另请参阅 MSDN sqlcmd 参考。它使选项的输出感到羞耻。/?
评论
'""' + col1 + '""' AS col1
这不是故意的吗?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 实用工具文档页。
上页示例:
bcp.exe MyTable out "D:\data.csv" -T -c -C 65001 -t , ...
评论
bcp
不包括标题(列名),但它比(根据我的经验)快 ~10 倍。对于真正的大数据,你可以用它来获取数据,并使用(select top 0 * from ...)来获取标题,然后将它们组合起来。sqlcmd
bcp
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 将其过滤掉,从而删除该行。请注意,它并不完美,因为它正在过滤掉 - 如果输出中只有一列,它将不起作用,并且它还会过滤掉包含该字符串的合法行。-,-
评论
使用 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
Invoke-Sqlcmd 是 sqlcmd.exe
的 PowerShell 等效项。它输出的不是文本,而是 System.Data.DataRow
对象。
该参数的工作方式类似于 sqlcmd.exe 的参数。向其传递一个描述要导出的数据的 SQL 查询。-Query
-Q
该参数的工作方式类似于 sqlcmd.exe 的参数。向其传递包含要导出的数据的数据库的名称。-Database
-d
该参数的工作方式类似于 sqlcmd.exe 的参数。向其传递包含要导出的数据的服务器的名称。-Server
-S
Export-CSV
是一个 PowerShell cmdlet,用于将泛型对象序列化为 CSV。它随 PowerShell 一起提供。
该参数禁止显示不属于 CSV 格式的额外输出。默认情况下,cmdlet 会写入包含类型信息的标头。当您稍后使用 时,它可以让您知道对象的类型,但它会混淆需要标准 CSV 的工具。-NoTypeInformation
Import-Csv
该参数的工作方式类似于 sqlcmd.exe 的参数。-Path
-o
该参数的工作方式类似于 sqlcmd.exe 的 or 参数。默认情况下,Export-Csv 仅输出 ASCII 字符,并用问号替换所有其他字符。请改用 UTF8 来保留所有字符并与大多数其他工具保持兼容。-Encoding
-f
-u
与 sqlcmd.exe 或 bcp.exe 相比,此解决方案的主要优点是无需破解命令即可输出有效的 CSV。Export-Csv cmdlet 会为您处理所有操作。
主要缺点是,在沿管道传递结果集之前,会先读取整个结果集。确保有足够的内存来存储要导出的整个结果集。Invoke-Sqlcmd
对于数十亿行,它可能无法顺利运行。如果这是一个问题,您可以尝试其他工具,或者使用 System.Data.SqlClient.SqlDataReader 类推出自己的高效版本。Invoke-Sqlcmd
SQL Server 版本之间的差异
从 SQL Server 2016 开始,作为 SqlServer
模块的一部分提供。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
如果使用旧的 SQLPS 模块遇到困难,则 参数的完整路径是最安全的。Export-Csv
-Path
若要使示例适用于 SQL Server 2008 和 2008 R2,请完全删除该行,并使用 sqlps.exe 实用工具而不是标准 PowerShell 主机。#Requires
评论
BCP 的替代选项:
exec master..xp_cmdshell 'BCP "sp_who" QUERYOUT C:\av\sp_who.txt -S MC0XENTC -T -c '
这个答案建立在 @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()
通常带有 bcp
实用程序(作为 的一部分),默认情况下导出为 CSV。sqlcmd
mssql-tools
用法:
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
评论
上面的答案几乎为我解决了这个问题,但它没有正确创建解析的 CSV。
这是我的版本:
sqlcmd -S myurl.com -d MyAzureDB -E -s, -W -i mytsql.sql | findstr /V /C:"-" /B > parsed_correctly.csv
有人说它已经过时了,而支持一些 PowerShell 替代方案,却忘记了这不仅适用于 Windows。我在 Linux 上(在 Windows 上时,无论如何我都避免使用 PS)。sqlcmd
sqlcmd
说了这么多,我确实觉得更容易。bcp
由于以下 2 个原因,您应该在 CMD 中运行我的解决方案:
- 查询中可能有双引号
有时需要登录用户名和密码来查询远程 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
尝试使用 python 包将逗号分隔的输出后处理为有效的 csv。sqlcmd-csv
https://github.com/shadiakiki1986/sqlcmd-csv
sqlcmd ... -s, ...
pip install git+https://github.com/shadiakiki1986/sqlcmd-csv.git
sqlcmd_csv out.txt out.csv
评论