LoginSignup
29
44

More than 5 years have passed since last update.

PowerShellでCSVデータを読み取り、付け足し、保存する

Posted at

やりたいこと

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より全然使いやすいと思います。

29
44
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
44