2013-02-16 87 views
1

我試圖導出數據庫表爲文本(CSV-ISH)爲以後的大批量插入。 在ISO格式yyyy-mm-dd中使用日期會少得多。我相信,我終於說服SQL Server Express在其導入期望英國格式(儘管灰色的服務器屬性被困在「英語(美國)」中,無論我做什麼)。我將用戶帳戶更改爲英國,這對應於我的PowerShell CSV導出格式。 但我寧願使用ISO格式來解決問題。設置在PowerShell export-csv中使用的日期格式?

目前,填充SELECT * FROM Table的表變量並將其導入到Export-CSV中後,日期以dd/mm/yyyy格式出現在生成的文本文件中。

我怎樣才能迫使PowerShell腳本使用ISO日期格式中的所有語句(即沒有指定格式在每一個人的命令),所以我需要出口-CSV將它們寫?我一直在圈子裏看了幾個小時,看着'文化'和事情,但我完全困惑!

回答

7

嘗試格式化你的文化:

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 
+1

這是每個會話,所以你需要添加到$配置文件或在每個腳本 – jbockle 2013-02-16 13:19:31

+0

ansgar,閱讀問題。他想將其設置爲默認 – 2013-02-17 17:30:54

0

非常感謝jbockle您的幫助,我現在可以從辦公室(SQL服務器2005)的數據家裏,並將其導入相同的表(從創建的.sql腳本)在我家Win XP機器上運行SQL Server 2008 Express。

在該第一示例中,該表被直接導出到CSV然後事後清理。轉換線功能可以去除「引號是因爲BULK INSERT不喜歡他們,也增加了額外的反引號分隔符每一行的開始和結束,這樣它就可以替換1任何True0任何False(在任何地方)因爲布爾人很棘手:)
(它似乎與相鄰的布爾人有問題,所以此通道運行兩次以將它們全部拖拽起來!)
最後一行修剪不需要的`從開始&每個末尾行。

## 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,因爲它不工作)。

在此第二實例中,另一種方法是採取 - 此時的數據表複製到一個新的,其中每個列是字符串類型,使得每個字段可以沒有問題類型進行調整。然後將複製數據表導出爲CSV,然後我們只需處理它即可刪除不需要的雙引號。

這次我們有機會替換「在任何字符串字段中,因此雙重引號或逗號都不會打破它們,例如像約翰」JJ「史密斯這樣的名字將最終成爲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文件。

+0

我剛編輯了代碼。我不再學習原來的多通道文件讀/寫方法,而是多瞭解了一點,現在都是在一個文件IO通道中完成的,它調用一個函數來執行一次命中的行轉換。由於至少需要一個此類傳遞,因此不需要嘗試修改$ sqldt數據表 - 浪費的工作量。但我可能會試驗:) – 2013-02-17 18:31:15

0

FYI我已經做了相當多的與BULK插入到SQL中使用PowerShell中,我發現,來解決這個問題最簡單的方法是:

  1. 將數據導出到CSV與出口-CSV - 分隔符「`t」 - 這是一個製表符分隔的文件。
  2. 批量插入時,插入到所有列設置爲NVARCHAR(MAX)數據類型的臨時表中。
  3. 創建具有適當數據類型集的第二臨時表。
  4. 從Temp表1中選擇記錄到Temp表2中,用SQL中的REPLACE命令將所有引號替換爲無。

對於我來說,當我遇到一個包含自己數據中的標籤的列時,這隻會真的讓我失望,但是如果遇到它們,我只需用這些列中的空格替換標籤。

由於我正在處理數千行CSV文件,這是我可以做到的最簡單的方式,而且最快的速度明智,因爲它都基於設置。