Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
比较两个CSV,匹配两列或更多列上的列,使用powershell从两个CSV导出特定列_Powershell_Csv - Fatal编程技术网

比较两个CSV,匹配两列或更多列上的列,使用powershell从两个CSV导出特定列

比较两个CSV,匹配两列或更多列上的列,使用powershell从两个CSV导出特定列,powershell,csv,Powershell,Csv,我有两个CSV left.csv Ref_ID,First_Name,Last_Name,DOB 321364060,User1,Micah,11/01/1969 946497594,User2,Acker,05/28/1960 887327716,User3,Aco,06/26/1950 588496260,User4,John,05/23/1960 565465465,User5,Jack,07/08/2020 right.csv First_Name,Last_Name,DOB,City

我有两个CSV

left.csv

Ref_ID,First_Name,Last_Name,DOB
321364060,User1,Micah,11/01/1969
946497594,User2,Acker,05/28/1960
887327716,User3,Aco,06/26/1950
588496260,User4,John,05/23/1960
565465465,User5,Jack,07/08/2020
right.csv

First_Name,Last_Name,DOB,City,Document_Type,Filename
User1,Micah,11/01/1969,Parker,Transcript,T4IJZSYO.pdf
User2,Acker,05/28/1960,,Transcript,R4IKTRYN.pdf
User3,Aco,06/26/1950,,Transcript,R4IKTHMK.pdf
User4,John,05/23/1960,,Letter,R4IKTHSL.pdf
最终结果:

Combined.csv

Ref_ID,First_Name,Last_Name,DOB,Document_Type,Filename
321364060,User1,Micah,11/01/1969,Parker,Transcript,T4IJZSYO.pdf
946497594,User2,Acker,05/28/1960,Transcript,R4IKTRYN.pdf
887327716,User3,Aco,06/26/1950,Transcript,R4IKTHMK.pdf
588496260,User4,John,05/23/1960,Letter,R4IKTHSL.pdf
我需要在First_Name、Last_Name、DOB上匹配它们,然后从left.csv返回Ref_ID、First_Name、Last_Name、DOB,从right.csv返回Document_Type、Filename

使用比较对象:它只返回其中一个CSV中的列,而不返回两个CSV中的列

使用:这是我最大的希望,但这只允许我匹配一列,我需要匹配多个列(不知道如何匹配多个列)


我不知道从这里到哪里去,接受建议。

您可以从每个csv创建自己的密钥,然后使用此密钥从每个csv添加到新的哈希表

在调试器(ISE或VSCode)中逐步完成此操作,并根据需要进行调整。。。 根据数据的完整性,根据需要添加适当的错误检查。 下面的一些语句只是为了调试,以便您可以在运行时检查发生了什么

# Ref_ID,First_Name,Last_Name,DOB
$csv1 = @'
321364060,User1,Micah,11/01/1969
946497594,User2,Acker,05/28/1960
887327716,User3,Aco,06/26/1950
588496260,User4,John,05/23/1960
565465465,User5,Jack,07/08/2020
'@

# First_Name,Last_Name,DOB,City,Document_Type,Filename
$csv2 = @'
User1,Micah,11/01/1969,Parker,Transcript,T4IJZSYO.pdf
User2,Acker,05/28/1960,,Transcript,R4IKTRYN.pdf
User3,Aco,06/26/1950,,Transcript,R4IKTHMK.pdf
User4,John,05/23/1960,,Letter,R4IKTHSL.pdf
'@

# hashtable
$data = @{}

$c1 = $csv1 -split "`r`n"
$c1.count

foreach ($item in $c1)
{
    $fields = $item -split ','
    $key = $fields[1]+$fields[2]+$fields[3]
    $key

    # add new hashtable for given key
    $data.Add($key, [ordered]@{})

    # add data from c1 to the hashtable
    $data[$key].ID = $fields[0]
    $data[$key].First = $fields[1]
    $data[$key].Last = $fields[2]
    $data[$key].DOB = $fields[3]
}

$c2 = $csv2 -split "`r`n"
$c2.count

foreach ($item in $c2)
{
    $fields = $item -split ','
    $key = $fields[0]+$fields[1]+$fields[2]
    $key

    # add data from c2 to the hashtable
    $data[$key].Type = $fields[4]
    $data[$key].FileName = $fields[5]
}

$data.Count

foreach ($key in $data.Keys)
{
    '====================='
    $data[$key]
}

您可以从每个csv创建自己的密钥,然后使用此密钥从每个csv添加到新的哈希表

在调试器(ISE或VSCode)中逐步完成此操作,并根据需要进行调整。。。 根据数据的完整性,根据需要添加适当的错误检查。 下面的一些语句只是为了调试,以便您可以在运行时检查发生了什么

# Ref_ID,First_Name,Last_Name,DOB
$csv1 = @'
321364060,User1,Micah,11/01/1969
946497594,User2,Acker,05/28/1960
887327716,User3,Aco,06/26/1950
588496260,User4,John,05/23/1960
565465465,User5,Jack,07/08/2020
'@

# First_Name,Last_Name,DOB,City,Document_Type,Filename
$csv2 = @'
User1,Micah,11/01/1969,Parker,Transcript,T4IJZSYO.pdf
User2,Acker,05/28/1960,,Transcript,R4IKTRYN.pdf
User3,Aco,06/26/1950,,Transcript,R4IKTHMK.pdf
User4,John,05/23/1960,,Letter,R4IKTHSL.pdf
'@

# hashtable
$data = @{}

$c1 = $csv1 -split "`r`n"
$c1.count

foreach ($item in $c1)
{
    $fields = $item -split ','
    $key = $fields[1]+$fields[2]+$fields[3]
    $key

    # add new hashtable for given key
    $data.Add($key, [ordered]@{})

    # add data from c1 to the hashtable
    $data[$key].ID = $fields[0]
    $data[$key].First = $fields[1]
    $data[$key].Last = $fields[2]
    $data[$key].DOB = $fields[3]
}

$c2 = $csv2 -split "`r`n"
$c2.count

foreach ($item in $c2)
{
    $fields = $item -split ','
    $key = $fields[0]+$fields[1]+$fields[2]
    $key

    # add data from c2 to the hashtable
    $data[$key].Type = $fields[4]
    $data[$key].FileName = $fields[5]
}

$data.Count

foreach ($key in $data.Keys)
{
    '====================='
    $data[$key]
}
试试这个。
它还有一些其他功能,以及基于多个列的连接:

$Left = ConvertFrom-Csv @"
Ref_ID,First_Name,Last_Name,DOB
321364060,User1,Micah,11/01/1969
946497594,User2,Acker,05/28/1960
887327716,User3,Aco,06/26/1950
588496260,User4,John,05/23/1960
565465465,User5,Jack,07/08/2020
"@

$Right = ConvertFrom-Csv @"
First_Name,Last_Name,DOB,City,Document_Type,Filename
User1,Micah,11/01/1969,Parker,Transcript,T4IJZSYO.pdf
User2,Acker,05/28/1960,,Transcript,R4IKTRYN.pdf
User3,Aco,06/26/1950,,Transcript,R4IKTHMK.pdf
User4,John,05/23/1960,,Letter,R4IKTHSL.pdf
"@

$Left | Join $Right `
    -On First_Name, Last_Name, DOB `
    -Property Ref_ID, Filename, First_Name, DOB, Last_Name `
    | Format-Table

Last_Name    Ref_ID DOB                    Filename     First_Name
---------    ------ ---                    --------     ----------
Micah     321364060 1969-11-01 12:00:00 AM T4IJZSYO.pdf User1
Acker     946497594 1960-05-28 12:00:00 AM R4IKTRYN.pdf User2
Aco       887327716 1950-06-26 12:00:00 AM R4IKTHMK.pdf User3
John      588496260 1960-05-23 12:00:00 AM R4IKTHSL.pdf User4
试试这个。
它还有一些其他功能,以及基于多个列的连接:

$Left = ConvertFrom-Csv @"
Ref_ID,First_Name,Last_Name,DOB
321364060,User1,Micah,11/01/1969
946497594,User2,Acker,05/28/1960
887327716,User3,Aco,06/26/1950
588496260,User4,John,05/23/1960
565465465,User5,Jack,07/08/2020
"@

$Right = ConvertFrom-Csv @"
First_Name,Last_Name,DOB,City,Document_Type,Filename
User1,Micah,11/01/1969,Parker,Transcript,T4IJZSYO.pdf
User2,Acker,05/28/1960,,Transcript,R4IKTRYN.pdf
User3,Aco,06/26/1950,,Transcript,R4IKTHMK.pdf
User4,John,05/23/1960,,Letter,R4IKTHSL.pdf
"@

$Left | Join $Right `
    -On First_Name, Last_Name, DOB `
    -Property Ref_ID, Filename, First_Name, DOB, Last_Name `
    | Format-Table

Last_Name    Ref_ID DOB                    Filename     First_Name
---------    ------ ---                    --------     ----------
Micah     321364060 1969-11-01 12:00:00 AM T4IJZSYO.pdf User1
Acker     946497594 1960-05-28 12:00:00 AM R4IKTRYN.pdf User2
Aco       887327716 1950-06-26 12:00:00 AM R4IKTHMK.pdf User3
John      588496260 1960-05-23 12:00:00 AM R4IKTHSL.pdf User4

已经有一些好的答案了,还有一个

将无数对象导入单个(dis)阵列:

使用
组对象
将它们组织为具有相同键值的组:

$keyProps = @('First_Name', 'Last_name', 'DOB')
$disarray | 
    Group-Object -Property $keyProps | 
    Where-Object Count -gt 1 |
然后合并对象,将任何缺少的属性添加到输出
$mergedObject

    ForEach-Object {
        $mergedObject = $_.group[0]
        foreach ($obj in $_.group[1..($_.group.count-1)]) {
            $newProps = ($obj | Get-Member -MemberType NoteProperty).name | 
                Where-Object {
                    $_ -notin ($mergedobject | Get-Member -MemberType NoteProperty).name
                } 
            foreach ($propName in $newProps) {
                $mergedObject | Add-Member -MemberType NoteProperty -Name $propName -Value $obj.$propName -Force
            }
        }
        Write-Output $mergedObject
    }
这与你已经得到的答案没有太大区别,但是消除“左”“右”的区别可能会有所帮助;上面的代码应该处理三个或多个抛出到
$disarray
中的源,合并包含相同
$keyProps
的所有对象


请注意,有一些拐角的情况需要考虑。例如,如果一个对象对用户具有“City=Chigago”,而另一个对象具有“City=newyork”,会发生什么情况

已经有了一些好的答案,下面是另一个

将无数对象导入单个(dis)阵列:

使用
组对象
将它们组织为具有相同键值的组:

$keyProps = @('First_Name', 'Last_name', 'DOB')
$disarray | 
    Group-Object -Property $keyProps | 
    Where-Object Count -gt 1 |
然后合并对象,将任何缺少的属性添加到输出
$mergedObject

    ForEach-Object {
        $mergedObject = $_.group[0]
        foreach ($obj in $_.group[1..($_.group.count-1)]) {
            $newProps = ($obj | Get-Member -MemberType NoteProperty).name | 
                Where-Object {
                    $_ -notin ($mergedobject | Get-Member -MemberType NoteProperty).name
                } 
            foreach ($propName in $newProps) {
                $mergedObject | Add-Member -MemberType NoteProperty -Name $propName -Value $obj.$propName -Force
            }
        }
        Write-Output $mergedObject
    }
这与你已经得到的答案没有太大区别,但是消除“左”“右”的区别可能会有所帮助;上面的代码应该处理三个或多个抛出到
$disarray
中的源,合并包含相同
$keyProps
的所有对象

请注意,有一些拐角的情况需要考虑。例如,如果一个对象对用户具有“City=Chigago”,而另一个对象具有“City=newyork”,会发生什么情况

添加我找到的答案:

$left = Import-Csv .\left.csv
$right = Import-Csv .\right.csv

$right | foreach { 
    $r = $_; 
    $left | where{ $_.First_Name -eq $r.First_Name -and $_.Last_Name -eq $r.Last_Name -and $_.DOB -eq $r.DOB } | 
        select Ref_Id, 
            First_Name, 
            Last_Name, 
            DOB, 
            @{Name="City";Expression={$r.City}}, 
            @{Name="Document_Type";Expression={$r.Document_Type}}, 
            @{Name="FileName";Expression={$r.FileName}}
} | format-table
添加我发现的答案:

$left = Import-Csv .\left.csv
$right = Import-Csv .\right.csv

$right | foreach { 
    $r = $_; 
    $left | where{ $_.First_Name -eq $r.First_Name -and $_.Last_Name -eq $r.Last_Name -and $_.DOB -eq $r.DOB } | 
        select Ref_Id, 
            First_Name, 
            Last_Name, 
            DOB, 
            @{Name="City";Expression={$r.City}}, 
            @{Name="Document_Type";Expression={$r.Document_Type}}, 
            @{Name="FileName";Expression={$r.FileName}}
} | format-table

做得很好,只是几件事。使用
-Passthru
将匹配的对象沿着管道向下传递到
ForEach
循环。然后在循环中再次使用
Compare Object
以另一种方式获得右侧对象,只需将缺少的属性添加到传递的左侧对象。然后在导出到CSV之前,选择*-Exclude SideIndicator。大量的缩短以适应,但这适用于代码Compare$left$right-Prop First_Name,Last_Name,DOB-Incl-Excl-PassThru |%{$iRight=Compare$right$|-Property First_Name,Last_Name,DOB-Incl-Excl-PassThru;$|添加成员“Document_Type”$iRight.Document_Type;$|添加成员“FileName”$iRight.FileName-PassThru}|选择*-排除侧指示器|导出Csv C:\Combined.Csv-NoType@TheMadTechnician您能在回答中输入您的代码吗?我不能完全理解您通过评论所做的所有更改。@Nas这看起来很棒,易于阅读,并且非常适合我将来可能需要的更改。我明天再试试,如果行得通的话,我会把它标记为被接受的答案给了你正确的答案,这很容易阅读,很容易适应,而且它支持多栏,即使标题不匹配。很棒的工作做得很好,只是几件事。使用
-Passthru
将匹配的对象沿着管道向下传递到
ForEach
循环。然后在循环中再次使用
Compare Object
以另一种方式获得右侧对象,只需将缺少的属性添加到传递的左侧对象。然后在导出到CSV之前,选择*-Exclude SideIndicator。大量的缩短以适应,但这适用于代码Compare$left$right-Prop First_Name,Last_Name,DOB-Incl-Excl-PassThru |%{$iRight=Compare$right$|-Property First_Name,Last_Name,DOB-Incl-Excl-PassThru;$|添加成员“Document_Type”$iRight.Document_Type;$|添加成员“FileName”$iRight.FileName-PassThru}|选择*-排除侧指示器|导出Csv C:\Combined.Csv-NoType@TheMadTechnician您能在回答中输入您的代码吗?我不能完全理解您通过评论所做的所有更改。@Nas这看起来很棒,易于阅读,并且非常适合我将来可能需要的更改。我明天再试试,如果行得通的话,我会把它标记为被接受的答案给了你正确的答案,这很容易阅读,很容易适应,而且它支持多栏,即使标题不匹配。顶部的csv数据仅供参考吗?这意味着我可以使用$csv1=导入csv left.csv吗?这其中的哪一部分与公共列匹配?试图确保我完全理解这一点。顶部的csv数据仅供参考吗?意思是我可以使用$csv1=导入csv左。