【问题标题】:Merge two text files by upserting records (update existing ones, insert new ones)通过更新记录合并两个文本文件(更新现有记录,插入新记录)
【发布时间】:2016-09-02 10:54:53
【问题描述】:

我正在寻找一个 UNIX shell 解决方案来在两个文本文件之间执行相当于 SQL MERGE(或 UPSERT)的操作,其中一些字段是关键字段,而其他字段可以更新/覆盖。

输入数据

这是我的原始数据:

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

其中前三个字段(ProductCustomerDate)是关键字段,后两个字段(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

第一条和第三条记录应该覆盖现有的行(更新QuantityAmount),而第二条和第三条记录应该作为新行插入。

期望的输出

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

我正在寻找使用sortuniqawkperl 的快速解决方案。

【问题讨论】:

  • 然后我在发布这个问题两分钟后找到了awk '!a[$0]++'

标签: shell unix awk merge uniq


【解决方案1】:

当第 1、第 2、第 3 个字段的索引在 file2 中匹配时,您希望覆盖 file1 中的行。也就是说,file2 比 file1 具有“偏好”,因此如果 file1 中的一行在 file2 中没有对应关系,则只会打印它。

如果是这样,如何打印所有两个文件,从 file2 开始,并跳过那些重复 file1-file2-file3-wise 的行?然后,通过管道对排序后的输出进行排序:

$ awk -F";" '!seen[$1, $2, $3]++' 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

【讨论】:

  • @EdMorton 一般来说,我们什么时候应该避免使用逗号来创建索引?就在我们有像1 23 这样也可以是12 3 的行时?总是使用FS 来防止它不安全吗?
  • 12 31 23 的问题发生在您在下标之间没有放置任何内容以便它们都连接到 123 时。使用,FS 可以解决这个问题。当你要打印数组索引和/或你有多个引用索引的地方(例如{key=$1 FS $2} seen[key]++{map[key]=$NF; ...} END{for (i in map) print i, map[i]})时,你应该使用FS(或OFS,如果合适的话),否则你应该使用,为了简洁.
  • @EdMorton 一如既往的帮助!
【解决方案2】:
$ awk -F\; '{a[$1 FS $2 FS $3]= $4 FS $5} 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[$1 FS $2 FS $3] = $4 FS $5    # 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]
}

【讨论】:

  • 我正要说 FS 太多了...而你刚刚删除了它。好一个!我们都有相同的输出,我也喜欢你提供了一个很好的解释,干得好!
  • 是的,我在test.awk 和命令行中修复了它,但忘记了发布的版本... TGIF。
  • 您的 NR==FNR 和其他块是相同的,因此您不需要 2 个单独的块。只需摆脱 NR==FNR{...} 块,剩下的内容对这两个文件都可以正常工作。
  • 大声笑。我真的需要在发布之前开始校对这些内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-15
  • 2015-08-14
  • 1970-01-01
相关资源
最近更新 更多