如何根据第四个文件更新三个 CSV 文件

如何根据第四个文件更新三个 CSV 文件

我有四个数据集文件,我想根据第四个文件中的值更新一组三个文件。

  1. 文件_1包含名称。
  2. 文件_2他们的数字 ID。
  3. 文件_3包含 id 来自文件_1文件_2,以及每对 id 组合对应的值。
  4. 文件_4包含一些新名称组合的值。

我需要做的是附加文件_4的新名字为文件_1文件_2,并自动增量地为它们创建 id。然后将值插入文件_3根据新的 ID 组合。问题很简单,如下面的示例所解释的那样,使问题变得有点复杂的是逗号分隔的子字段的存在,例如“1,2,3”在一些数据集s。

我需要使用脚本来实现此目的,尽管我意识到它可能更容易使用sql

文件_1

nid,vname
1,name1
2,name2
3,name3

文件_2

did,dname
1,"s1,s2,s3"
2,s4
3,"s5,s6"

文件_3

nid,did,value
1,1,aa
1,2,gg
1,3,tt
2,1,aa
2,2,ag
2,3,at
3,1,aa
3,2,tt

文件_4

new_name,new_dataset,value
name1,"s7,s8",aa
name2,"s9,s10",gg
name8,"s1,s2,s3",aa

因此,三个更新的文件应如下所示:

文件_1_更新

nid,vname
1,name1
2,name2
3,name3
4,name8

文件_2_更新

did,dname
1,"s1,s2,s3"
2,s4
3,"s5,s6"
4,"s7,s8"
5,"s9,s10"

文件_3_更新

nid,did,value
1,1,aa
1,2,gg
1,3,tt
1,4,aa
2,1,aa
2,2,ag
2,3,at
2,5,gg
3,1,aa
3,2,tt
4,1,aa

答案1

假设数据与您发布的完全相同,那么您可以在普通 bash 中执行以下操作。 (警告:就地修改文件。测试前请小心备份。)

管理前两个文件的几个函数:

next_id() {
  file="$1"
  # assumes file is sorted by id
  echo $(( $(tail -n 1 $file|cut -d, -f1) + 1 ))
}

假设文件1文件2在 id 列上排序,这将获取最后一行的第一部分并将其递增 1,生成下一个 id。

find_or_create_id() {
  file="$1"
  item="$2"
  # check if we already have that item
  id=$(grep -m 1 ",$item$" "$file" 2> /dev/null)
  if [[ $? -ne 0 ]] ; then
    # generate the next id, append
    id=$(next_id "$file")
    echo "$id,$item" >> "$file"
  else
    # got it already
    id=${id/,*}
  fi
  echo "$id"
}

这将在前两个文件之一中查找项目(vname 或 dname)。如果找到,则返回现有的 id。如果没有,则生成下一个 id 并将其存储回文件中。

一旦你得到了正确的子字符串,主要部分就非常简单:

while read line ; do
  col1=${line/,*}  # everything up to first ,
  col3=${line//*,} # everything after last ,
  col2=${line%,*}  # everything after first ,
  col2=${col2#*,}  # everything before last ,
  id1=$(find_or_create_id file1 "$col1")
  id2=$(find_or_create_id file2 "$col2")
  # don't insert duplicates
  if ! grep -m 1 -q "^$id1,$id2," file3 ; then
    echo "$id1,$id2,$col3" >> file3
  fi
done < <(tail -n +2 file4)

这会不是按顺序插入最后一个文件,您将在末尾附加新行。


话虽这么说,如果这些文件中的任何一个文件的大小都很大,那么数据库将是合适的。如果您不需要数据库服务器,请考虑 SQLite。

假设您不关心顺序 ID(只是它们是不同的),并且您已integer primary key autoincrement为表 1 和表 2 添加了 ID(加上 vname 和 dname 上的唯一键),则更新看起来像(很可能是比该方法更微妙的方法insert or ignore):

insert or ignore into tab1(vname) select distinct vname from tab4;
insert or ignore into tab2(dname) select distinct dname from tab4;

insert or ignore into tab3(id1,id2,value)
  select tab1.id, tab2.id, tab4.value
  from tab4
  left join tab1 on tab1.vname = tab4.vname
  left join tab2 on tab2.dname = tab4.dname;

SQLite 可以很好地处理"文件中的 。

.separator ,
.import fileX tabX

做正确的事情™,至少对于您那里的样品是这样。

简单架构:

create table tab1 (id integer primary key autoincrement, vname text);
create unique index tab1_vname on tab1(vname);

create table tab2 (id integer primary key autoincrement, dname text);
create unique index tab2_dname on tab2(dname);

create table tab3 (id1 int, id2 int, value text,
                   constraint tab3_pk primary key(id1, id2));

create table tab4 (vname text, dname text, value text);

答案2

这是2/3的答案,使用*尼克斯软件工具。 文件_1_更新:

head -n 1 file_1 ; \
{ tail -n +2 file_1 | cut -d ',' -f 2 ; \
  tail -n +2 file_4 | cut -d ',' -f 1 ; } | \
sort -n | uniq | nl -s ',' | tr -d ' '

输出:

nid,vname
1,name1
2,name2
3,name3
4,name8

文件_2_更新:

head -n 1 file_2 ; \
{ tail -n +2 file_2 | cut -d ',' -f 2- ; \
  tail -n +2 file_4 | cut -d ',' -f 2- | \
  rev | cut -d ',' -f 2- | rev ; } | \
sort -n | uniq | nl -s ',' | tr -d ' '

输出:

did,dname
1,"s1,s2,s3"
2,s4
3,"s5,s6"
4,"s7,s8"
5,"s9,s10"

相关内容