やりたいこと
order.csv
に 担当列を追加し、担当.csv
を参照しながら商品担当者分行を追加して、export.csv
に出力する。
つまり、 DBでやれ てな事をやります。
order.csv
order_no | item_no | item_name |
---|---|---|
1 | "001" | アイスコーヒー |
2 | "002" | A定食 |
3 | "004" | ハンバーグ定食 |
2 | "002" | A定食 |
3 | "004" | ハンバーグ定食 |
担当.csv
item_no | staff_name |
---|---|
001 | 山田 |
002 | 山田;吉田;古田 |
003 | 田中 |
004 | 岩田;石澤 |
export.csv
order_no | item_no | item_name | 担当 |
---|---|---|---|
1 | 001 | アイスコーヒー | 山田 |
2 | 002 | A定食 | 山田 |
2 | 002 | A定食 | 古田 |
2 | 002 | A定食 | 吉田 |
3 | 004 | ハンバーグ定食 | 石澤 |
3 | 004 | ハンバーグ定食 | 岩田 |
実装
環境
Windows7 SP1,PowerShell 3.0
こんな感じになりました。
# Import-CSVと同時に列を追加する。
$orderDat = Import-Csv -Encoding UTF8 -Path ".\order.csv" |
Select-Object *,@{Name='担当';Expression={''}}
$staffDat = Import-Csv -Encoding UTF8 -Path ".\担当.csv"
# Main logic
[System.Array] $ExportDat = $null
# すべての入荷データを確認
foreach($currentDat in $orderDat){
# 担当スタッフを検索する。できればnull判定まで一行でやりたいが。。。
$staff = $($staffDat | Where-Object{$_.item_no -eq $currentDat.item_no}).staff_name
if($staff -eq $null){$staff = ""}
# 重複と空白を削除し、文字列の配列にする。
$staffArray = $($staff.Split(";")) | Sort-Object | Get-Unique | Where-Object{$_ -ne "" -and $_ -ne $null}
# CSVデータを追加する。
if($staffArray -ne $null){
foreach($st in $staffArray){
$currentDat.担当 = $st
# そのまま代入すると参照になってしまうのでExport用の変数を用意する。
$tmpDat = New-Object psobject
# 元データから情報をいれる。
$currentDat.psobject.Properties | ForEach-Object{
$tmpDat | Add-Member -MemberType $_.MemberType -Name $_.Name -Value $_.Value
}
# 出力用配列にデータを追加する。
$ExportDat = $ExportDat + $tmpDat
}
}else {
$tmpDat = New-Object psobject
$currentDat.psobject.Properties | ForEach-Object{
$tmpDat | Add-Member -MemberType $_.MemberType -Name $_.Name -Value $_.Value
}
$ExportDat += $tmpDat
}
}
# データをソートする。
$ExportDat = $ExportDat | Sort-Object order_no
# CSVファイルを出力する。
$ExportDat | Export-Csv -Encoding Default -NoTypeInformation -Force -Path ".\export.csv"
要点メモ
CSVのインポートとEncode
Import-CSV
の一文でさっくりデータをとれます。
ただし、-Encoding
がPowershell2.0ではうまく使えないのでWindows7SP1環境には別途3.0をインストールする必要があります。
これが結構な罠でそこそこ嵌った。
$orderDat = Import-Csv -Encoding UTF8 -Path ".\order.csv"
CSVデータへの列追加は、Select-Object
で行う。
| Select-Object *,@{Name='担当';Expression={''}}
出力用の変数は型指定で
ちゃんと指定しないと行を足す時に動いてくれません。
[System.Array] $ExportDat = $null
ディープコピーは根性で
これが一番嵌った。StackOverflowで調べた結果このようになった。
まず psobject
を新規に作成し(そもそもpsobjectが何なのかわかっていない)
$tmpDat = New-Object psobject
Object[]
である currentDat
のプロパティを ForEach-Object
ですべて Add-Member
する。
$currentDat.psobject.Properties | ForEach-Object{
$tmpDat | Add-Member -MemberType $_.MemberType -Name $_.Name -Value $_.Value
}
晴れてディープコピー完了となるので、$ExportDat
配列に追加する。
$ExportDat = $ExportDat + $tmpDat
もう、わからない感がひしひししてます。もっとスマートにやりたい・・・
CSVExportには-NoTypeInformationを
エキスポートも超簡単、一行、PowerShell最高
$ExportDat | Export-Csv -Encoding Default -NoTypeInformation -Force -Path ".\export.csv"
-Encoding
を気をつける事は前述したが、追加で -NoTypeInformation
を付けることを忘れずに。
巷の解説ページではこのオプションがついていないことが殆どだが、これを付けないと出力されたCSVの一行目にいらぬ情報がつく。
実務ではいらない情報が付いて来るのがデフォルトになっているのだ・・・
蛇足:PowerShellのエディタについて
巷のPowerShell関連情報ではあまりエディタについて語られていない。
PowerShellを使う 変態 プロにはそんな情報はいらないのだろう。
あまり前置きが長くても何なので、結論だけ。
PowerShellエディタはVisual Studio Code!!
ISEより全然使いやすいと思います。