2

後で一括挿入するために、データベース テーブルをテキスト (CSV 風) にエクスポートしようとしています。日付を ISO 形式の yyyy-mm-dd にすると、手間が大幅に軽減されます。私は最終的に、インポートで英国形式を期待するようにSQL Server Expressを説得したと思います(グレー表示されたサーバープロパティが何をしても「英語(米国)」のままになっているにもかかわらず)。ユーザー アカウントを英国に変更しました。これは、PowerShell CSV エクスポート形式に対応しています。しかし、問題を完全に回避するには、ISO形式を使用したいと思います。

現時点では、a からテーブル変数を入力し、SELECT * FROM Tableそれを Export-CSV にパイプすると、生成されたテキスト ファイルに日付がdd/mm/yyyy形式として出力されます。

ISOPowerShell スクリプトがすべてのステートメントで形式の日付を使用するように強制するにはどうすればよいですか(つまり、個々のコマンドで形式を指定しないでください)、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

jbockle さんの助けに感謝します。これで、オフィス (SQL サーバー 2005) からデータを持ち帰り、SQL Server 2008 Express を実行している自宅の Win XP マシンの同じテーブルに (CREATE .sql スクリプトから) インポートできるようになりました。

この最初の例では、テーブルは CSV に直接エクスポートされ、その後クリーンアップされます。Convert-Line 関数は " 引用符を削除します。これは、BULK INSERT がそれらを好まないためです。また、各行の開始と終了に追加のバッククォート区切り文字を追加して、any と any を (行の任意の場所で) 置き換えることができるようTrue1Falseます0。ブール値はトリッキーです :)
(隣接するブール値に問題があるようです。そのため、このパスを 2 回実行してそれらをすべて消去します!)
最後の行では、各行の先頭と末尾から不要な ` を削除します。

##  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

テーブル結合が引き続き機能するように、元の ID フィールドが保持されます。

数値、テキスト、ブール値、日付のフィールド タイプで正常に動作します。

BULK INSERT はフィールド名を含む最初の行について文句を言いますが、これは無視できる警告です (FIRSTROW = 2 は機能しないので試してはいけません)。

この 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"

空のテーブルがこのスクリプトを壊すことはありません。0 バイトの CSV ファイルを取得するだけです。

于 2013-02-16T22:22:51.137 に答える
0

参考までに、PowerShell を使用して SQL への BULK Inserting をかなり実行しましたが、問題に対処する最も簡単な方法は次のとおりであることがわかりました。

  1. Export-Csv -Delimited "`t" を使用してデータを CSV にエクスポートします。これはタブ区切りのファイルです。
  2. 一括挿入の場合、すべての列が NVARCHAR(MAX) データ型に設定されている一時テーブルに挿入します。
  3. 適切なデータ型が設定された 2 番目の一時テーブルを作成します。
  4. 一時テーブル 1 から一時テーブル 2 へのレコードを選択し、SQL の REPLACE コマンドを使用してすべての引用符を何も置き換えません。

これは、自分のデータ内にタブを含む列に出くわしたときにのみ本当に失敗しますが、列に出くわした場合は、それらの列のタブをスペースに置き換えるだけです。

何千もの行を含む CSV ファイルを扱っていたので、これが最も簡単な方法であり、すべてセットベースであるため最も高速でした。

于 2013-02-17T21:28:23.117 に答える