合并两个 CSV 文件

Merge two CSV files

我想将两个 header 相同的 CSV 文件合并为一个 CSV 文件。 我有两个这样的文件,如下所示,即 DevData.csvProdData.csv 具有相同的 cfname 和不同的 IDs

    ID                   cfname
    -------------------- -----------------------------------
                   10201 Risk ID
                   10202 Issue ID
                   10203 Dependency ID
                   10204 Server ID
                   10205 Parent Application ID
                   10206 Application Service ID
                   10207 Application Supportability
                   10208 Application Compatibility
                   10300 Application Status
                   10301 Contact ID Type 2
                   10302 Contact ID Type 3
                   10303 Contact ID Type 4
                   10304 Business Service Manager
                   10308 Server Location Name:
                   10309 Rack Position:
                   10310 Rack Number:
                   10311 Data Centre
                   10312 Server Group
(14 rows affected)

我想创建以下格式的新 CSV:

DevID                ProdID cfname
-------------------- ------ -----------------------------------
               10201 201    Risk ID
               10202 202    Issue ID
               10203 203    Dependency ID
               10204 204    Server ID
               10205 205    Parent Application ID
               10206 206    Application Service ID
               10207 207    Application Supportability
               10208 208    Application Compatibility
               10300 209    Application Status
               10301 210    Contact ID Type 2
               10302 211    Contact ID Type 3
               10303 212    Contact ID Type 4
               10304 213    Business Service Manager
               10308 214    Server Location Name:

以下是我当前的代码,但它导出第一个文件的数据,并在其下方导出下一个文件的数据。

function Merge-CSVFiles {
    [cmdletbinding()]
    param(
        [string[]]$CSVFiles
    )

    $Output = @();
    foreach ($CSV in $CSVFiles) {
        if (Test-Path $CSV) {
            $FileName = [System.IO.Path]::GetFileName($CSV)
            $temp = Import-CSV -Path $CSV |
                    select ID, cfname, ID, cfname, @{Expression={$FileName}}
            $Output += $temp
        } else {
            Write-Warning "$CSV : No such file found"
        }
    }
    $Output | Export-Csv -Path $OutputFile -NoTypeInformation
    Write-Output "$OutputFile successfully created"
}

Merge-CSVFiles -CSVFiles "C:\Users\ECSAdmin\Desktop\Proddata.csv", "C:\Users\ECSAdmin\Desktop\Devdata.csv" -OutputFile "C:\Users\ECSAdmin\Desktop\Mergedata.csv"

可以对两个集合做一个嵌套的foreach循环,但是两个避免执行时间相对于输入大小呈指数增长,更好的策略是加载一个集合进入哈希表(使用公共 属性 cfname 作为键)然后遍历另一个并将两个连接起来:

$DevData = @'
ID,cfname
10201,Risk ID
10202,Issue ID
10203,Dependency ID
10204,Server ID
10205,Parent Application ID
10206,Application Service ID
10207,Application Supportability
10208,Application Compatibility
10300,Application Status
10301,Contact ID Type 2
10302,Contact ID Type 3
10303,Contact ID Type 4
10304,Business Service Manager
10308,Server Location Name:
10309,Rack Position:
10310,Rack Number:
10311,Data Centre
10312,Server Group
'@ |ConvertFrom-Csv

$ProdData = @'
ID,cfname
201,Risk ID
202,Issue ID
203,Dependency ID
204,Server ID
205,Parent Application ID
206,Application Service ID
207,Application Supportability
208,Application Compatibility
209,Application Status
210,Contact ID Type 2
211,Contact ID Type 3
212,Contact ID Type 4
213,Business Service Manager
214,Server Location Name:
'@ |ConvertFrom-Csv

# throw one set into a hashtable
# we can use this as a lookup table for the other set
$ProdTable = @{}
foreach($line in $ProdData){
    $ProdTable[$line.cfname] = $line.ID
}

# Output the DevData with the appropriate ProdData value
$DevData |Select-Object @{Label='DevID';Expression={$_.ID}},@{Label='ProdID';Expression={$ProdTable[$_.cfname]}},cfname |Export-Csv .\new.csv -NoTypeInformation

您可以试试这个简单的命令管道:

Out-file -FilePath '.\csv3.csv' -InputObject "ProdID,ID,cfname"; ForEach($CFName In $Csv1) { $Csv2.Where({$_.cfname -eq $CFName.cfname}) | %{ "$($_.ProdID),$($CFName.ID),$($_.cfName)" } | Out-File .\csv3.csv -Append}

我假设 Csv1.csv 是第一个包含 ID 和 cfname 列的文件,第二个文件 Csv2.csv 包含 ProdID 和 cfname 列。这将生成第三个文件 csv3.csv,其中包含合并的内容

由于您使用 sqlcmd 从 SQL 服务器导出数据,因此您需要添加参数 -W-s"," 让您的命令创建实际的 CSV 输出:

sqlcmd -S server -d db -E -Q "query" -W -s"," -o output.csv

一旦您有了实际的 CSV 文件,您就可以像这样处理它们:

# create a hashtable from the second CSV, so you can look up IDs by the
# values in the "cfname" column
$proddata = @{}
Import-Csv 'C:\path\to\ProdData.csv' | ForEach-Object {
  $proddata[$_.cfname] = $_.ID
}

Import-Csv 'C:\path\to\DevData.csv' |
  Select-Object @{n='DevID';e={$_.ID}},
                @{n='ProdID';e={$proddata[$_.cfname}}, cfname |
  Export-Csv 'C:\path\to\merged.csv'

这确实假定您的 ProdData.csv 仅包含 cfname 也出现在 DevData.csv 中的值,并且您的 cfname 值至少在 ProdData.csv 中是唯一的].双向合并更复杂,因为您需要检查 $proddata 中的 whick keys 在 DevData.csv 中不存在并相应地附加它们。如果您的 cfname 值不是唯一的,您将无法对齐记录。