从多个CSV文件构建Excel电子表格

时间:2018-11-28 23:29:45

标签: excel powershell csv

我有1张Excel工作簿,一张纸和3个csv文件。工作表具有固定数量的列(带有标题)和不同数量的行。一栏包含一个“ ID”字段,最后三栏为空白。每个csv都有不同数量的列,但每个都有一个“ ID”字段,该字段应与Excel工作表中的“ ID”字段匹配。尽管Excel工作表可能具有相同ID的多个实例,但CSV中没有重复的ID。例如:

Excel文件

ID:     Name:   Color:  Location:   Age:    Siblings:
123     Bob     Red
234     Sally   Green
345     Donald  Orange
123     Bob     Black

CSV1

ID:     Name:   Place:  Animal: Location:   Car:
123     Bob     Here    Dog     Up          Ferarri
234     Sally   There   Cat     Down        Porsche
345     Donald  Nowhere Squid   Right       Yugo

CSV2

ID:     Name:   Place:  Age:    
123     Bob     Here    50      
234     Sally   There   45      
345     Donald  Nowhere 100

CSV3

ID:     Siblings:
123     Five
234     Three
345     Eight

目标是根据匹配的ID将CSV文件中特定列的数据添加到excel文件中。预期的输出将是以下Excel文件:

ID:     Name:   Color:  Location:   Age:    Siblings:
123     Bob     Red     Up          50      Five
234     Sally   Green   Down        45      Three
345     Donald  Orange  Right       100     Eight
123     Bob     Black   Up          50      Five

我花了很多时间试图找出最有效(快速)的方法来完成这项工作,并认为我遇到了麻烦。到目前为止(相关部分)我所拥有的:

# Pull relevant data from csv files together #
$rtFile = $selectedDirectory + "\\" + "*RT*.csv"
$seFile = $selectedDirectory + "\\" + "*SE*.csv"
$lmFile = $selectedDirectory + "\\" + "*LM*.csv"

$rtCSV = Import-Csv $rtFile | select ID, LOCATION
$seCSV = Import-Csv $seFile | select ID, AGE
$lmCSV = Import-Csv $lmFile | select ID, SIBLINGS

$rtCSV | ForEach {$_ | Add-Member 'AGE' $null}
$rtCSV | ForEach {$_ | Add-Member 'SIBLINGS' $null}

foreach ($record in $rtCSV) {
    $record.'AGE' = $seCSV | Where {$_.ID -eq $record.ID} | Select -Expand 'AGE'
    $Record.'SIBLINGS' = $lmCSV | Where {$_.ID -eq $record.ID} | Select -Expand 'SIBLINGS'
}

# Add Data to Excel Sheet #
$WorkSheet.Activate()
$range = $WorkSheet.Range("C1").EntireColumn

foreach ($searchStr in $rtCSV.ID) {
    $search = $range.Find($searchStr)

    if ($search -ne $null) {
        $firstAdr = $search.Address(0, 0, 1, 0)

        do {
            $WorkSheet.Cells.Item($search.row,17).Value() = $rtCSV[$search.row].LOCATION
            $WorkSheet.Cells.Item($search.row,18).Value() = $rtCSV[$search.row].AGE
            $WorkSheet.Cells.Item($search.row,19).Value() = $rtCSV[$search.row].SIBLINGS

            $search = $range.FindNext($search)
        } while ($search -ne $null -and $search.Address(0, 0, 1, 0) -ne $firstAdr)
    }
}

花了我一段时间,但我终于弄清楚了为什么上述方法不起作用。尽管$search.row确实返回了Excel文档中的匹配行(因此可以很好地确定要在哪个单元格中插入数据),但它不会为{{1 }}。那么如何确保每次ID匹配时都为LOCATION,AGE和SIBLINGS插入正确的值?

如果在当前的架构下不可能,那么还有另一种(也许更好,更有效)的方法吗?一般来说,Excel文件的行数不得超过1000。

2 个答案:

答案 0 :(得分:0)

如果您不介意安装其他模块以简化工作,则强烈建议使用dfinke's Import Excel module。安装if之后,实现目标的代码将很简单:

# cd C:\SO\53529676
$rtCSV = Import-Csv .\csv1.csv | select ID, LOCATION
$seCSV = Import-Csv .\csv2.csv | select ID, AGE
$lmCSV = Import-Csv .\csv3.csv | select ID, SIBLINGS
$excel = Import-Excel .\Excel1.xlsx

foreach ($record in $excel) {
  $record.'LOCATION' = ($rtCSV | Where {$_.ID -eq $record.ID}).LOCATION
  $record.'AGE' = ($seCSV | Where {$_.ID -eq $record.ID}).AGE
  $Record.'SIBLINGS' = ($lmCSV | Where {$_.ID -eq $record.ID}).SIBLINGS
}

$excel | Export-Excel .\Excel2.xlsx

答案 1 :(得分:0)

如果您最关心的是性能,请考虑两件事:

将“查找表”(csv1,csv2,csv3)转换为哈希表,因此查找速度很快(有点类似于数据库中的索引编制)

将所有数据保留在平面文件(csv)中,以避免依赖关系并使脚本简单高效。然后,您可以将数据链接到电子表格以作为应用视图       格式化是否需要(您可以在MS Access中从csv创建链接表和视图,然后将其馈送到Excel中的数据表)

下面是一个示例(为简单起见,使用其他一些伪文件)。您也可以在主循环中使用工作表对象(只需循环遍历行索引并更新单元格对象)。

# generate hashtables
$person = @{}
$location = @{}
Import-Csv location.csv | foreach {$location.Add($_.id, @{zip=$_.zip; city=$_.city})}
Import-Csv person.csv | foreach {$person.Add($_.id, @{name=$_.name; age=$_.age})}

# loop through the main file
Import-Csv main.csv | foreach {
    $id = $_.id
    $_.name = $person[$id].name
    $_.age = $person[$id].age
    $_.city = $location[$id].city
    $_.zip = $location[$id].zip
    Write-Output $_ } | Convertto-Csv | Out-File mainOut.csv