通过插入记录合并两个文本文件(更新现有记录,插入新记录)
Merge two text files by upserting records (update existing ones, insert new ones)
我正在寻找一个 UNIX shell 解决方案来执行两个文本文件之间的 SQL MERGE
(或 UPSERT
),其中一些字段是关键字段,其他字段可以是updated/overwritten.
输入数据
这是我的原始数据:
AA;123;2016-01-31;1;456.53
AA;123;2016-02-01;1;75.24
AB;123;2000-08-08;1;756.1
AB;456;2016-07-07;2;8.24
CC;123;2007-07-21;15;10.34
CC;456;2009-09-09;9;943.65
CC;789;2005-04-23;1;1345.6
其中前三个字段(Product、Customer 和 Date)是关键字段, 最后两个字段 (Quantity 和 Amount) 可以更新。
这是我的第二个文件,它只包含新的和更新的数据:
AA;123;2016-01-31;7;983.63
AA;123;2016-08-24;17;1687.73
CC;456;2009-09-09;11;2161.65
DD;91;2016-08-03;5;98.48
两个文件的排序方式:
sort -t';' -k1 -k2 -k3
第一条和第三条记录应覆盖现有行(更新数量和金额),而第二条和第三条记录应作为新行插入。
期望输出
AA;123;2016-01-31;7;983.63
AA;123;2016-08-24;17;1687.73
AA;123;2016-02-01;1;75.24
AB;123;2000-08-08;1;756.1
AB;456;2016-07-07;2;8.24
CC;123;2007-07-21;15;10.34
CC;456;2009-09-09;11;2161.65
CC;789;2005-04-23;1;1345.6
DD;91;2016-08-03;5;98.48
我正在寻找一些使用 sort
、uniq
或 awk
和 perl
的快速解决方案。
$ awk -F\; '{a[ FS FS ]= FS } END {PROCINFO["sorted_in"]="@ind_str_asc"; for (i in a) print i FS a[i]}' file1 file2
AA;123;2016-01-31;7;983.63
AA;123;2016-02-01;1;75.24
AA;123;2016-08-24;17;1687.73
AB;123;2000-08-08;1;756.1
AB;456;2016-07-07;2;8.24
CC;123;2007-07-21;15;10.34
CC;456;2009-09-09;11;2161.65
CC;789;2005-04-23;1;1345.6
DD;91;2016-08-03;5;98.48
解释:
{
a[ FS FS ] = FS # write records overwriting where needed
}
END {
PROCINFO["sorted_in"]="@ind_str_asc" # for sort order
for (i in a) # output indexed records
print i FS a[i]
}
当第 1、第 2、第 3 字段的索引在 file2 中匹配时,您想覆盖 file1 中的行。也就是说,file2 在 file1 上有 "preference",所以如果 file1 中的一行在 file2 中没有相应的内容,则只打印它。
如果是这样,如何打印所有两个文件,从 file2 开始,并跳过那些重复 file1-file2-file3-wise 的行?然后,通过管道对排序后的输出进行排序:
$ awk -F";" '!seen[, , ]++' f2 f1 | sort
AA;123;2016-01-31;7;983.63
AA;123;2016-02-01;1;75.24
AA;123;2016-08-24;17;1687.73
AB;123;2000-08-08;1;756.1
AB;456;2016-07-07;2;8.24
CC;123;2007-07-21;15;10.34
CC;456;2009-09-09;11;2161.65
CC;789;2005-04-23;1;1345.6
DD;91;2016-08-03;5;98.48
我正在寻找一个 UNIX shell 解决方案来执行两个文本文件之间的 SQL MERGE
(或 UPSERT
),其中一些字段是关键字段,其他字段可以是updated/overwritten.
输入数据
这是我的原始数据:
AA;123;2016-01-31;1;456.53
AA;123;2016-02-01;1;75.24
AB;123;2000-08-08;1;756.1
AB;456;2016-07-07;2;8.24
CC;123;2007-07-21;15;10.34
CC;456;2009-09-09;9;943.65
CC;789;2005-04-23;1;1345.6
其中前三个字段(Product、Customer 和 Date)是关键字段, 最后两个字段 (Quantity 和 Amount) 可以更新。
这是我的第二个文件,它只包含新的和更新的数据:
AA;123;2016-01-31;7;983.63
AA;123;2016-08-24;17;1687.73
CC;456;2009-09-09;11;2161.65
DD;91;2016-08-03;5;98.48
两个文件的排序方式:
sort -t';' -k1 -k2 -k3
第一条和第三条记录应覆盖现有行(更新数量和金额),而第二条和第三条记录应作为新行插入。
期望输出
AA;123;2016-01-31;7;983.63
AA;123;2016-08-24;17;1687.73
AA;123;2016-02-01;1;75.24
AB;123;2000-08-08;1;756.1
AB;456;2016-07-07;2;8.24
CC;123;2007-07-21;15;10.34
CC;456;2009-09-09;11;2161.65
CC;789;2005-04-23;1;1345.6
DD;91;2016-08-03;5;98.48
我正在寻找一些使用 sort
、uniq
或 awk
和 perl
的快速解决方案。
$ awk -F\; '{a[ FS FS ]= FS } END {PROCINFO["sorted_in"]="@ind_str_asc"; for (i in a) print i FS a[i]}' file1 file2
AA;123;2016-01-31;7;983.63
AA;123;2016-02-01;1;75.24
AA;123;2016-08-24;17;1687.73
AB;123;2000-08-08;1;756.1
AB;456;2016-07-07;2;8.24
CC;123;2007-07-21;15;10.34
CC;456;2009-09-09;11;2161.65
CC;789;2005-04-23;1;1345.6
DD;91;2016-08-03;5;98.48
解释:
{
a[ FS FS ] = FS # write records overwriting where needed
}
END {
PROCINFO["sorted_in"]="@ind_str_asc" # for sort order
for (i in a) # output indexed records
print i FS a[i]
}
当第 1、第 2、第 3 字段的索引在 file2 中匹配时,您想覆盖 file1 中的行。也就是说,file2 在 file1 上有 "preference",所以如果 file1 中的一行在 file2 中没有相应的内容,则只打印它。
如果是这样,如何打印所有两个文件,从 file2 开始,并跳过那些重复 file1-file2-file3-wise 的行?然后,通过管道对排序后的输出进行排序:
$ awk -F";" '!seen[, , ]++' f2 f1 | sort
AA;123;2016-01-31;7;983.63
AA;123;2016-02-01;1;75.24
AA;123;2016-08-24;17;1687.73
AB;123;2000-08-08;1;756.1
AB;456;2016-07-07;2;8.24
CC;123;2007-07-21;15;10.34
CC;456;2009-09-09;11;2161.65
CC;789;2005-04-23;1;1345.6
DD;91;2016-08-03;5;98.48