使用 Powershell 从 SQL Server 2008 R2 导出到固定宽度的文本文件
Posted
技术标签:
【中文标题】使用 Powershell 从 SQL Server 2008 R2 导出到固定宽度的文本文件【英文标题】:Using Powershell to export from a SQL Server 2008 R2 to a fixed width text file 【发布时间】:2013-05-31 08:35:20 【问题描述】:我有一个 Powershell 脚本,它针对 SQL Server 2008R2 数据库执行 2 个 SQL 语句,目前它将数据放入 2 个 CSV 文件中。
#Connection Strings
$Database = "*****SQL"
$Server = "L*******2008R2"
#SMTP Relay Server
#Export File
$AttachmentPath = "\\c******.csv"
$TempAttachmentPath = "\\cd*****.cvs"
$AttachmentPath2 = "\\p**********.cvs"
$TempAttachmentPath2 = "\\m**********.cvs"
# Connect to SQL and query data, extract data to SQL Adapter
$SqlQuery = "Select Distinct
s*****t.s*****e,
p*****n.p******y,
p******n.p*****l,
p*****n.p*****m + Replicate(' ', (50 - Len(p*****n.p*****am))),
p*****n.p*****am,
Case When Len(a*****s.*****en) > 0 Then RTrim(ad****s.a*****n) + ', ' Else ''
End + ad****ss.a****t + Replicate(' ',(100 - len(Case When Len(ad*****s.a****n) > 0 Then RTrim(ad*****s.a******n) + ', ' Else ''
End + a******s.a*****t))),
a*******s.a******y,
a*******s.a******n,
a*******s.a******d,
p*****on.p******b
From
p*****n Inner Join
s*****t On p****.pe****d = st****t.p****y Inner Join
a*****s On pe****n.a****ey = a****s.a****d Inner Join
e****l On s*****t.s*****d = e*****l.s*****y Inner Join
c*****o On e****l.c*****y = c*****e.c*****d
Where
s*****t.pa*****y = (Select
Max(s.p*****y)
From
st*****nt s
Where
s.s*****de = st*****t.s******e) And
p*****n.p*****e = 'S**T' And
c****e.p*****ey >= 34
Order By
s******t.s******de"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Data Source=$Server;Initial Catalog=$Database;Integrated Security = True"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$nRecs = $SqlAdapter.Fill($DataSet)
$nRecs | Out-Null
#Populate Hash Table
$objTable = $DataSet.Tables[0]
#Export Hash Table to CSV File
$objTable | Export-CSV $TempAttachmentPath
gc $TempAttachmentPath | ? $_ -notlike '#TYPE System.Data.DataRow' | sc $AttachmentPath
(gc $AttachmentPath) | % $_ -replace '"', "" | out-file $AttachmentPath -Fo -En ascii
Remove-Item $TempAttachmentPath
$SqlQuery = "Select
RTrim(c*****e.csecode) + Replicate(' ', 24 - Len(c*****e.****de)),
Left(RTrim(c****e.c******c), 50) + Replicate(' ', 50 - Len(Left(c*****e.c*****c,50))),
s*****s.pa*****r
From
co****e Inner Join
s****s On ****e.p****ey = s****rs.p****d
Where
c*****e.p*****y >= 36"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Data Source=$Server;Initial Catalog=$Database;Integrated Security = True"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$nRecs = $SqlAdapter.Fill($DataSet)
$nRecs | Out-Null
#Populate Hash Table
$objTable = $DataSet.Tables[0]
#Export Hash Table to CSV File
$objTable | Export-CSV $TempAttachmentPath2
gc $TempAttachmentPath2 | ? $_ -notlike '#TYPE System.Data.DataRow' | sc $AttachmentPath2
(gc $AttachmentPath2) | % $_ -replace '"', "" | out-file $AttachmentPath2 -Fo -En ascii
Remove-Item $TempAttachmentPath2
此代码有效,但是有一个新请求。用户希望这些数据在一个没有分隔符的文本文件中,只是数据库中的列宽。
表 1
field1 Char(10)
field2 Char(12)
field3 Char(14)
Field4 Char(7)
文件中的数据:
Another One Bites Bites
我是 Powershell 新手,所以我需要一些帮助
谢谢保罗
【问题讨论】:
不是一个解决方案,而是一个注释 - 最后,您将在其中剥离#TYPE System.Data.DataRow
- 如果您在调用 export-csv
时使用 -notypeinformation
,则不必这样做.您还可以通过参数指定分隔符和编码到Export-CSV
。
【参考方案1】:
尝试使用 Powershell 的 export-csv 和 ADO.NET 困难重重。 SQL Server 和 SSIS 附带的 BCP.exe 提供了生成固定长度导出文件的本机能力。这是一个使用 bcp.exe 的示例,您可以在 Powershell 中运行它(创建和插入测试生成除外):
USE tempdb;
CREATE TABLE t1 (
charcol CHAR(16) NULL,
varcharcol VARCHAR(16) NULL,
varbinarycol VARBINARY(8)
);
GO
INSERT INTO t1 VALUES ('No blanks', 'No blanks', 0x00ee);
INSERT INTO t1 VALUES ('Trailing blank ', 'Trailing blank ', 0x00ee00);
GO
#Generate BCP format file
bcp tempdb..t1 format nul -c -f "C:\Users\Public\fixedlentext.fmt" -T -S MyServer
#Edit generated file
10.0
3
1 SQLCHAR 0 16 "\t" 1 charcol SQL_Latin1_General_CP1_CI_AS
2 SQLCHAR 0 16 "\t" 2 varcharcol SQL_Latin1_General_CP1_CI_AS
3 SQLCHAR 0 17 "\r\n" 3 varbinarycol ""
#Replace "\t" with "" for fixed length and save file
10.0
3
1 SQLCHAR 0 16 "" 1 charcol SQL_Latin1_General_CP1_CI_AS
2 SQLCHAR 0 16 "" 2 varcharcol SQL_Latin1_General_CP1_CI_AS
3 SQLCHAR 0 17 "\r\n" 3 varbinarycol ""
#bcp out fixed length using format file
bcp "SELECT * FROM tempdb..t1" queryout "C:\Users\Public\fixedlentext.txt" -c -T -SMyServer -f "C:\Users\Public\fixedlentext.fmt"
【讨论】:
【参考方案2】:这是可能的,但它会很丑。固定宽度的文件格式很难处理。
将所有内容保留到export-csv
。之后,您必须手动将内容转储到文件中。从 ADO.NET,您可以获得widths of each field。
获得每个字段的宽度后,您需要遍历DataSet
中的每一行,并为每个字段获取值,然后将其填充到所需的长度。为该行构造一个字符串,然后使用out-file
将其附加到您的输出文件中。
您也必须对标头执行相同的操作(并将其写入上段循环之前的输出文件) - 但是如果字段名称比其中包含的数据长怎么办?还是不需要标头?
这是很多额外的工作,而且它的运行速度会比您当前的脚本慢(尤其是在您修复当前脚本以使用 export-csv
和我在上面的评论中提到的适当参数之后)。
【讨论】:
以上是关于使用 Powershell 从 SQL Server 2008 R2 导出到固定宽度的文本文件的主要内容,如果未能解决你的问题,请参考以下文章
powershell 使用SQL文件和PowerShell从数据库中提取数据。设计用于SQL服务器并以CSV格式输出。看到这个链接:h
使用 Powershell 从 SQL Server 2008 R2 导出到固定宽度的文本文件
从 powershell 中删除 SQL Server 数据库