使用Powershell从SQL Server 2008 R2导出到固定宽度的文本文件

时间:2013-05-31 08:35:20

标签: sql sql-server-2008 powershell text-files

我有一个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的新手,所以我想要一些帮助

谢谢保罗

2 个答案:

答案 0 :(得分:3)

尝试使用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"

答案 1 :(得分:0)

这是可能的,但它会很难看。固定宽度的文件格式很难处理。

保持所有内容都领先于export-csv。在此之后,您必须手动将内容转储到文件中。从ADO.NET,您可以获得widths of each field

一旦获得每个字段的宽度,就需要遍历DataSet中的每一行,并为每个字段获取值,然后将其填充到所需的长度。为该行构造一个字符串,然后使用out-file将其附加到输出文件。

您也必须对标题执行相同的操作(并在上面的段落中的循环之前将其写入输出文件) - 但是如果字段名称比其中包含的数据长,该怎么办?或者标题不是必需的?

这是一项额外的工作,它会比你当前的脚本运行得慢(特别是当你修改当前脚本以使用export-csv和我在上面评论中提到的相应参数之后)。