合并多个CSV文件

4

所以我一整天都在攻击互联网,寻找一种将多个CSV文件合并的方法。无论我查找了哪种30多种PowerShell方法,我都遇到了问题。

我正在尝试以“完全连接”方式将多个CSV文件合并为一个。我需要从所有CSV文件中组合所有行和所有列,但要注意的是,我想根据共同标识符组合行。这个讨论:“通过共享列合并两个CSV文件”,正好做到了我想做的事情,但有两个例外。首先,它只适用于两个CSV文件,其次,如果两个CSV文件都不包含“名称”,它会删除行。即使它不在两个CSV文件中,我也想保留该行,并在另一个CSV中没有数据的地方创建空白条目。

CSV1.csv

Name,Attrib1,Attrib2

VM1,111,True
VM2,222,False

CSV2.csv

Name,AttribA,Attrib1

VM1,AAA,111
VM3,CCC,333

CSV3.csv

Name,Attrib2,AttribB

VM2,False,YYY
VM3,True,ZZZ

期望的合并结果:

Name,Attrib1,Attrib2,AttribA,AttribB

VM1,111,True,AAA,
VM2,222,False,,YYY
VM3,333,True,CCC,ZZZ

有人对这个有任何想法吗?如果您需要更多信息,请告诉我。

更新:这是我目前在SQLite shell中尝试的代码:

$db  = Join-Path $env:TEMP 'temp.db'
$dir = "C:\Users\UserName\Downloads\CSV Combination"
$outfile = Join-Path $dir 'combined.csv'

@"
CREATE TABLE a (Name varchar(20),OS varchar(20),IP varchar(20),Contact varchar(20),Application varchar(20));
CREATE TABLE b (Name varchar(20));
CREATE TABLE c (Name varchar(20),Quiesce varchar(20));
CREATE TABLE d (Name varchar(20),NoQuiesce varchar(20));
.mode csv
.import '$((Join-Path $dir csv1.csv) -replace '\\', '\\')' a
.import '$((Join-Path $dir csv2.csv) -replace '\\', '\\')' b
.import '$((Join-Path $dir csv3.csv) -replace '\\', '\\')' c
.import '$((Join-Path $dir csv4.csv) -replace '\\', '\\')' d
SELECT a.Name,a.OS,a.IP,a.Contact,a.Application,c.Quiesce,d.NoQuiesce
FROM a
  LEFT OUTER JOIN b ON a.Name = b.Name
  LEFT OUTER JOIN c ON a.Name = c.Name
  LEFT OUTER JOIN d ON a.Name = d.Name
UNION
SELECT b.Name,a.OS,a.IP,a.Contact,a.Application,c.Quiesce,d.NoQuiesce
FROM b
  LEFT OUTER JOIN a ON a.Name = b.Name
  LEFT OUTER JOIN c ON b.Name = c.Name
  LEFT OUTER JOIN d ON c.Name = d.Name
UNION
SELECT c.Name,a.OS,a.IP,a.Contact,a.Application,c.Quiesce,d.NoQuiesce
FROM c
  LEFT OUTER JOIN a ON a.Name = c.Name
  LEFT OUTER JOIN b ON b.Name = c.Name
  LEFT OUTER JOIN d ON c.Name = d.Name;
"@ | filesystem::"C:\Users\UserName\Downloads\CSV Combination\sqlite3.exe" $db >$outfile

Remove-Item $db

目前返回以下错误信息:

sqlite3.exe:错误:C:\ Users \ brandon.andritsch \ Downloads \ CSV Combination \ csv1.csv第1行:期望5列数据,但找到6列


你可以使用来自 PowerShell Gallery[Join-Object] cmdlet 来完成这个任务: Import-CSV .\CSV1.csv | Join (Import-CSV .\CSV2.csv) Hosts {$Right.$_} | Join (Import-CSV .\CSV3.csv) Hosts {$Right.$_} | Export-CSV .\combined.csv - iRon
3个回答

2
我创建了一个名为Merge-Object(别名Merge)的Join-Object代理命令,因为合并对象类似于SQLMERGE语句的情况经常出现。 Merge-Object命令的默认参数设置为:JoinType = 'Full'Property={{如果($Null -ne $RightIndex){$Right.$_} Else {$Left.$_}}}}。这意味着所有左侧对象都将使用右侧属性值进行更新,并且在左侧对象列表中不存在的右侧对象将添加到结果中。
Import-Csv CSV1.csv | 
Merge (Import-Csv CSV2.csv) -On Name | 
Merge (Import-Csv CSV3.csv) -On Name |
Format-Table

结果:

Name Attrib1 Attrib2 AttribA AttribB
---- ------- ------- ------- -------
VM1  111     True    AAA
VM2  222     False           YYY
VM3  333     True    CCC     ZZZ

1

您可以使用一个非常好的命令行工具:Miller(http://johnkerl.org/miller/doc/)。

使用

mlr --csv reshape -r "^A" -o item,value then reshape -s item,value \
then unsparsify --fill-with ""  *.csv

你有。
Name,Attrib1,Attrib2,AttribA,AttribB
VM1,111,True,AAA,
VM2,222,False,,YYY
VM3,333,True,CCC,ZZZ

作为输入,我已经使用了这3个文件。
Name,Attrib1,Attrib2
VM1,111,True
VM2,222,False

Name,Attrib2,AttribB
VM2,False,YYY
VM3,True,ZZZ

Name,AttribA,Attrib1
VM1,AAA,111
VM3,CCC,333

还有win exe https://github.com/johnkerl/miller/releases

关于命令的一些说明:

  • reshape -r "^A" -o item,value,将输入的CSV从宽格式转换为长格式,并将其应用于所有以“A”开头的字段;
  • reshape -s item,value,将前一个输出从长格式转换为宽格式;
  • unsparsify --fill-with "",管理所有输入记录中的字段名称。对于在给定记录中缺少但存在于其他记录中的字段名,填充值为“”。

请问您能否详细解释一下您编写的Miller命令?这个命令是做什么用的? - Fariman Kashani
嗨@FarimanKashani,该命令回答了上面的问题。我在回复末尾添加了一些注释。你想知道什么?你是在尝试使用它但无法正常工作吗? - aborruso
1
谢谢@aborruso,你写的笔记回答了我的问题。我使用它并且它有效了。只是想知道我正在做什么,这样我就可以向我的队友解释了。 - Fariman Kashani

0

试试这个:

$db  = Join-Path $env:TEMP 'temp.db'
$dir = "C:\some\folder"
$outfile = Join-Path $dir 'combined.csv'

@"
CREATE TABLE a (Name varchar(20),Attrib1 varchar(20),Attrib2 varchar(20));
CREATE TABLE b (Name varchar(20),AttribA varchar(20),Attrib1 varchar(20));
CREATE TABLE c (Name varchar(20),Attrib2 varchar(20),AttribB varchar(20));
.mode csv
.import '$((Join-Path $dir csv1.csv) -replace '\\', '\\')' a
.import '$((Join-Path $dir csv2.csv) -replace '\\', '\\')' b
.import '$((Join-Path $dir csv3.csv) -replace '\\', '\\')' c
SELECT a.Name,a.Attrib1,a.Attrib2,b.AttribA,c.AttribB
FROM a
  LEFT OUTER JOIN b ON a.Name = b.Name
  LEFT OUTER JOIN c ON a.Name = c.Name
UNION
SELECT b.Name,a.Attrib1,a.Attrib2,b.AttribA,c.AttribB
FROM b
  LEFT OUTER JOIN a ON a.Name = b.Name
  LEFT OUTER JOIN c ON b.Name = c.Name
UNION
SELECT c.Name,a.Attrib1,a.Attrib2,b.AttribA,c.AttribB
FROM c
  LEFT OUTER JOIN a ON a.Name = c.Name
  LEFT OUTER JOIN b ON b.Name = c.Name;
"@ | sqlite3 $db >$outfile

Remove-Item $db

你需要使用SQLite命令行工具进行操作。

嘿,Ansgar,感谢你提供这个脚本。我不知道我是否能够设置SQLite,因为我没有权限将其放置在System32目录中。我已经成功运行它(我想),使用本地配置文件目录,这是返回给我的错误:sqlite3.exe:错误:未知命令或无效参数:“import”。输入“.help”获取帮助 - user2600210
.import $((Join-Path $dir csv1.csv) -replace '\\', '\\') a .import $((Join-Path $dir csv2.csv) -replace '\\', '\\') b .import $((Join-Path $dir csv3.csv) -replace '\\', '\\') c这些是我使用的命令 - 我不确定 %PATH% 是什么意思,我没有看到后面跟着变量,当它位于当前工作目录中时,会出现以下错误:“sqlite3.exe” 不是 cmdlet、函数、脚本文件或可运行程序的名称。此外,没有办法格式化这个注释文本吗?这看起来很糟糕。 - user2600210
另外,我注意到我在中间弄糟了那段代码,并在重写时跳过了一部分。不过我想我明白了大致的意思,我会看看能否修复它。(我对编程不是很熟悉,还处于初学阶段哈哈)。 - user2600210
谢谢您的更新,我完全错过了。这个可以用,但是现在我遇到了以下错误:sqlite3.exe : Error: C:\\Users\\brandon.andritsch\\Downloads\\CSV Combination\\csv1.csv line 1: expected 5 columns of data but found 6 - user2600210
错误信息非常明显。您声明了一个只有5个字段的表,但是您的CSV有6列。表的字段必须与CSV的相应字段匹配(数字和名称)。 - Ansgar Wiechers
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接