2

我正在尝试将数据库表导出为文本(CSV-ish)以供以后批量插入。使用 ISO 格式 yyyy-mm-dd 的日期会少很多麻烦。我相信,我最终说服了 SQL Server Express 在其导入中使用英国格式(尽管无论我做什么,灰色的服务器属性都卡在“英语(美国)”中)。我将用户帐户更改为 British,这与我的 PowerShell CSV 导出格式相对应。但我宁愿使用 ISO 格式来解决问题。

目前,从 a 填充了一个表变量SELECT * FROM Table并将其通过管道传输到 Export-CSV 中,日期以dd/mm/yyyy格式在生成的文本文件中出现。

如何强制 PowerShell 脚本ISO在所有语句中使用格式日期(即在每个单独的命令中不指定格式),以便 Export-CSV 将根据需要编写它们?我已经在圈子里转了几个小时,看“文化”之类的东西,但我完全糊涂了!

4

3 回答 3

9

尝试格式化您的文化:

PS C:\> $(get-date).ToShortDateString()
2/16/2013
PS C:\> $(Get-Culture).DateTimeFormat.ShortDatePattern = 'yyyy-MM-dd'
PS C:\> $(get-date).ToShortDateString()
2013-02-16
于 2013-02-16T13:17:13.540 回答
0

仅供参考,我已经使用 PowerShell 对 SQL 进行批量插入,我发现解决该问题的最简单方法是:

  1. 使用 Export-Csv -Delimited "`t" 将数据导出到 CSV - 这是一个制表符分隔的文件。
  2. 批量插入时,插入到所有列都设置为 NVARCHAR(MAX) 数据类型的临时表中。
  3. 创建具有正确数据类型集的第二个临时表。
  4. 将 Temp Table 1 中的记录选择到 Temp Table 2 中,使用 SQL 中的 REPLACE 命令将所有引号替换为空。

只有当我遇到一个在其自己的数据中包含一个选项卡的列时,这才真正让我崩溃,这很痛苦,但如果我遇到这些列中的空格,我只会用空格替换这些选项卡。

当我处理包含数千行的 CSV 文件时,这是我能做到的最简单的方法,而且速度最快,因为它都是基于设置的。

于 2013-02-17T21:28:23.117 回答
0

非常感谢 jbockle 的帮助,我现在可以将数据从办公室(SQL Server 2005)带回家,并将其导入到我家运行 SQL Server 2008 Express 的 Win XP 机器上的相同表中(来自 CREATE .sql 脚本)。

在第一个示例中,表直接导出为 CSV,然后进行清理。Convert-Line 函数删除 " 引号,因为 BULK INSERT 不喜欢它们,并且还在每行的开头和结尾添加额外的反引号分隔符,以便它可以替换 any Truewith1和 any Falsewith 0(行上的任何地方),因为布尔值很棘手 :)
(相邻的布尔值似乎有问题,因此此通道运行两次以将它们全部清除!)
最后一行从每行的开头和结尾修剪不需要的 `。

##  PowerShell newbies : for scripts to run, you must first execute:  Set-ExecutionPolicy RemoteSigned
##  and then all scripts will work (it's a global setting, remembered once run)

$SQLDT = New-Object "System.Data.DataTable"
$path = "C:"
(Get-Culture).DateTimeFormat.ShortDatePattern="yyyy-MM-dd"   # temp setting, for dates in ISO format

function Convert-Line
{  param( [string]$line=$(throw 'a CSV line is required.'))
  ## add ` to start and end, combined with removing quotes
   $line = "``" + $line + "``" -replace "`"", ""
  ## swap Boolean True/False to 1 or 0
  ##  !! Need to do it twice, as it has trouble with adjacent ones!!
   $line = $line -replace "``True``","``1``" -replace "``False``","``0``"
   $line = $line -replace "``True``","``1``" -replace "``False``","``0``"
  ## return with trimmed off start/end delimiters
   $line.TrimStart("``").TrimEnd("``")
}

function Table-Export
{   param( [string]$table=$(throw 'table is required.'))

   ## Get whole SQL table into $SQLDT datatable
    $sqldt.reset()
    $connString = "Server=.\SQLEXPRESS;Database=Test1;Integrated Security=SSPI;"
    $da = New-Object "System.Data.SqlClient.SqlDataAdapter" ("select * from $table",$connString)
    [void]$da.fill($SQLDT)

   ## Export to CSV with ` delimiter
    $sqldt | Export-Csv $path\$table.CSV -NoTypeInformation -delimiter "``"

   ## read entire file, parse line by line, process line, write back out again
    (gc $path\$table.CSV) | Foreach-Object { Convert-Line -line $_ } | Set-Content $path\$table.CSV
}

# main...
Table-Export -table "Table1"
Table-Export -table "Table2"
Table-Export -table "Table3etc"

这很好地使用 SQL 导入

DELETE FROM table1;
BULK INSERT table1 FROM 'C:\table1.csv' WITH (KEEPIDENTITY, FIELDTERMINATOR = '`');
DELETE FROM table2;
BULK INSERT table2 FROM 'C:\table2.csv' WITH (KEEPIDENTITY, FIELDTERMINATOR = '`');
-- etc, all tables

保留原始身份字段以使表连接仍然有效。

适用于字段类型:数字、文本、布尔值、日期。

BULK INSERT 会抱怨包含字段名称的第一行,但这是一个可忽略的警告(不要费心尝试 FIRSTROW = 2,因为它不起作用)。

在第二个示例中,采用了另一种方法——这一次将 DataTable 复制到一个新的数据表中,其中每一列都是字符串类型,以便可以调整每个字段而不会出现类型问题。然后将复制数据表导出为 CSV,然后我们需要做的就是处理它以删除不需要的双引号。

这次我们有机会在任何字符串字段中替换 ",因此双引号或逗号都不会破坏它们,例如,像 John "JJ" Smith 这样的名字最终会变成 John 'JJ' Smith,希望这是可以接受的。

$SQLDT = New-Object "System.Data.DataTable"
$path = "C:"
(Get-Culture).DateTimeFormat.ShortDatePattern="yyyy-MM-dd"   # temp setting, for dates in ISO format

function Table-Export
{   param( [string]$table=$(throw 'table is required.'))

   ## Get whole SQL table into $SQLDT datatable
    $sqldt.reset()
    $connString = "Server=.\SQLEXPRESS;Database=Test1;Integrated Security=SSPI;"
    $da = New-Object "System.Data.SqlClient.SqlDataAdapter" ("select * from $table",$connString)
    [void]$da.fill($SQLDT)

   ## Copy $SqlDt DataTable to a new $DT2 copy, with all columns now String type
    $DT2 = New-Object "System.Data.DataTable"
    $sqldt.columns | Foreach-Object { $DT2.Columns.Add($_.Caption) > $null }

   ## copy all $SqlDt rows to the new $DT2
   ## and change any " double quote in any field to a ' single quote, to preserve meaning in text fields
   ##  ( or you could use an odd char and replace in SQL database later, to return to " )
    For($i=0;$i -lt $sqldt.Rows.Count;$i++)
    { $DT2.Rows.Add() > $null
      For($i2=0;$i2 -lt $sqldt.Columns.Count;$i2++)
      { $DT2.Rows[$i][$i2] = $SQLDT.Rows[$i][$i2] -replace "`"","'" }
    }

  ## If any $SqlDt column was Boolean...
  ## use column name.. and for all rows in the new $DT2 : convert True/False to 1/0
   $sqldt.columns | Foreach-Object {
     If ($_.DataType.Name -EQ "Boolean")
     { $ColName = $_.Caption
       For($i=0;$i -lt $sqldt.Rows.Count;$i++)
       { If ($DT2.Rows[$i][$ColName] -EQ "True") { $DT2.Rows[$i][$ColName]="1" }
         If ($DT2.Rows[$i][$ColName] -EQ "False") { $DT2.Rows[$i][$ColName]="0" }
       }
     }
   }

   ## Export to CSV with ` delimiter
    $DT2 | Export-Csv $path\$table.CSV -NoTypeInformation -delimiter "``"

   ## read entire file, parse line by line, remove all ", write back out again
   (gc $path\$table.CSV) | Foreach-Object {$_ -replace "`"", "" } | Set-Content $path\$table.CSV
}

# main...
Table-Export -table "Table1"
Table-Export -table "Table2"
Table-Export -table "Table3etc"

空表不会破坏这个脚本,你只会得到一个零字节的 CSV 文件。

于 2013-02-16T22:22:51.137 回答