【问题标题】:Compare 2 Columns in CSV and Create a New Column If it matches比较 CSV 中的 2 列,如果匹配则创建一个新列
【发布时间】:2020-07-01 16:06:01
【问题描述】:

我有一个 Powershell 脚本,它正在对多个数据库进行 SQL 查询。 它将结果吐出到我桌面上的 CSV 文件中。 我希望 Powershell 脚本比较其中的 2 个列,然后在它们匹配时创建一个新列。

这只是节省了我每次在 excel 中进行比较的时间。

我只是对 powershell 了解不够,无法做到这一点。

CSV 中的当前结果是这样的。

    Name      PhoneNumber       PhoneNumberInDB2    
   Person 1    1112223333          1112223333
   Person 2    4445556666          7778889999

我希望脚本修改 csv 以执行此操作。

    Name      PhoneNumber       PhoneNumberInDB2    Match?
   Person 1    1112223333          1112223333         Y
   Person 2    4445556666          7778889999         N

我见过几个脚本如何比较多个 csv 并创建一个新的...但我宁愿只修改从 SQL 查询创建的那个。

如果有帮助...这里是实际 CSV 文件的副本和粘贴,我编辑了电话号码以保护客户...我正在查看 csv 中的 exel。

    ID  Phone   DB2Phone
5521350 1112223333  1112223333

从记事本:

"ID","Phone","PhoneID"
"5521350","1112223333","1112223333"

【问题讨论】:

  • 这不是 CSV
  • 我看不出它怎么不是 CSV..
  • @Bnd10706 - 如果它是 CSV,那么这些值将不会在列标题下方居中。无论分隔符是什么,该布局都不是从 CharacterSeparatedValue 文件中获得的。 ///// 你从$QueryResult.GetType()得到什么?
  • 我已格式化以便更好地查看。
  • 用记事本打开csv并复制粘贴

标签: powershell


【解决方案1】:

如果我没看错,也许您可​​以使用Select-Object 将属性添加到传入对象。听起来您正在比较的 2 个属性在任何给定时间都在同一个对象中。所以,你应该能够把它归结为一个管道......

类似:

$Data = Import-Csv "file.csv" |
Select-Object *,
    @{Name = 'Match'; Expression = { If( $_.PhoneNumber -eq $_.PhoneNumberInDB2 ){ 'Y' } Else { 'N' } } }

注意:我删除了“?”在新的属性(列)名称上。

如果您需要重新导出以重新导出到同一个 Csv 文件,只需将 $Data 传送到 Export-Csv 即可:

$Data = Import-Csv "file.csv" |
Select-Object *,
    @{Name = 'Match?'; Expression = { If( $_.PhoneNumber -eq $_.PhoneNumberInDB2 ){ 'Y' } Else { 'N' } } }

$Data | Export-Csv "file.csv" -NoTypeInformation

以上假设您想重新使用文件名,如果您想更改名称,您可以将其放在单个管道中,例如:

Import-Csv "file.csv" |
Select-Object *,
    @{Name = 'Match?'; Expression = { If( $_.PhoneNumber -eq $_.PhoneNumberInDB2 ){ 'Y' } Else { 'N' } } } | 
Export-Csv "file_new.csv" -NoTypeInformation

注意:此修订版不需要$Data。因为它都在管道上,所以内存效率更高。虽然这通常不是问题,除非文件很大。

【讨论】:

  • 这似乎正在运行,但我没有得到任何结果或错误。如果可以的话,CSV 命名匹配中没有列...
  • 好的,我在一个新的 PS 脚本中尝试过,但仍然无法比较...抱歉,我对 PS 的了解不够,无法理解为什么不这样做
  • 我玩了几次,分别在 SQL 之后运行脚本,但仍然没有得到任何结果。我不确定这个 csv 是否将 SQL 中的这些列标题分类为标题。
  • 它的编写方式是将对象存储在一个变量中。所以它不会产生任何输出,当然也不会改变文件。我将使用稍微修改的版本更新答案以重新创建文件。
  • 好的,谢谢...我有多个文件,长度超过 4000 行,这将为我节省大量时间
【解决方案2】:
$Data = Import-Csv "file.csv"
ForEach ($obj in $Data) {
$hashtable = [ordered]@{}
ForEach ($property in $obj.PSObject.properties.name) { $hashtable[$property] = $obj.$property }
$hashtable["match?"] = If ($obj.'PhoneNumber' -eq $obj.'PhoneNumberInDB2') {"Y"} Else {"N"}
$Data = $Data -ne $obj
$Data += New-Object -TypeName PSObject -Property $Hashtable
}

【讨论】:

  • 感谢您的帮助.. 尝试此操作时确实出现错误。方法调用失败,因为 [System.Management.Automation.PSObject] 不包含名为“op_Addition”的方法。 At Phone List.ps1:97 char:1 + $Data += New-Object -TypeName PSObject -Property $Hashtable + ~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (op_Addition:String) [], RuntimeException + FullyQualifiedErrorId : MethodNotFound
  • 你的 csv 文件格式是什么?好像您没有导入正确的文件。
  • 我看到了这种方法的方法,但我认为它的路很长。没有理由综合创建哈希表,尤其是在以后转换为对象时。 PowerShell 有几种本机方法可以将附加属性附加到对象。您还应该避免使用 += 运算符来附加数组。
  • 同意,你的方法要优雅得多。
【解决方案3】:

这里还有另一种方法来完成这项工作...... [grin] 它的作用......

  • 在 CSV 文件中进行虚假读取
    当您准备好实际执行此操作时,只需将整个 #region/#endregion 块替换为 Import-CSV 调用即可。
  • 遍历集合
  • 创建具有所需属性的新对象
  • 比较两个电话号码并将其保存到SamePhoneNumber 属性
    如果需要,您可以用N/Y 替换那些False/True 项目。只需在第 19 行和第 20 行交换注释标记即可。如果您要进行更多处理,False/True 内容比单纯的字母效果更好,因为它会在 PoSh 中自动转换为布尔值。
  • 将新对象发送到OutStuff 集合
  • 在屏幕上显示

代码...

#region >>> fake reading in a CSV file
#    in real life, use Import-CSV
$InStuff = @'
"ID","Phone","PhoneID"
"5521350","1112223333","1112223333"
"2020202","2020202020","2000000002"
"3030303","3030303030","3030303030"
"4040404","4040404040","4000000004"
'@ | ConvertFrom-Csv
#endregion >>> fake reading in a CSV file

$OutStuff = foreach ($IS_Item in $InStuff)
    {
    [PSCustomObject]@{
        ID = $IS_Item.Id
        Phone = $IS_Item.Phone
        PhoneId = $IS_Item.PhoneId
        # if you want `N/Y` instead of `False/True`, swap the comment markers for lines 19 & 20
        SamePhoneNumber = $IS_Item.Phone -eq $IS_Item.PhoneId
        #SamePhoneNumber = @('N', 'Y')[$IS_Item.Phone -eq $IS_Item.PhoneId]
        }
    }

$OutStuff

布尔输出 ...

ID      Phone      PhoneId    SamePhoneNumber
--      -----      -------    ---------------
5521350 1112223333 1112223333            True
2020202 2020202020 2000000002           False
3030303 3030303030 3030303030            True
4040404 4040404040 4000000004           False

使用N/Y 输出...

ID      Phone      PhoneId    SamePhoneNumber
--      -----      -------    ---------------
5521350 1112223333 1112223333 Y              
2020202 2020202020 2000000002 N              
3030303 3030303030 3030303030 Y              
4040404 4040404040 4000000004 N
 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 2021-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多