2016-09-02 5 views
0

2つのテキストファイルの間にSQL MERGE(またはUPSERT)と同等の処理を実行するUNIXシェルソリューションを探しています。他のフィールドは更新/上書きすることができます。レコードを更新して2つのテキストファイルを結合する(既存のものを更新する、新しいものを挿入する)

入力データ

これは私の元のデータである:最初の3つのフィールド(製品カスタマー)がキーフィールドです

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 

、そして最後に2つのフィールド(数量および)を更新することができます。

これが唯一の新規および更新されたデータが含まれている私の第二のファイルです:両方のファイルがでソートされている

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 

第一及び第三のレコードは、既存の行を上書きする必要があります(更新数量および金額)、2番目と3番目のレコードは新しい行として挿入する必要があります。私はsortuniqまたはawkperlを使用していくつかの簡単な解決策を探しています

所望の出力

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 

+0

をそして私が見つけた[awkの ' '![$ 0] ++''](http://unix.stackexchange.com/questions/159695/how -does-awk-a0-work)を入力してください。 –

答えて

3

あなたが第一、第二、第三のフィールドのインデックスがFILE2に一致したときFILE1の行を上書きします。つまり、file2はfile1よりも「preference」を持っているため、file2の対応がない場合はfile1の行だけが出力されます。

もしそうなら、file2から始まり、file1-file2-file3-wiseを繰り返す行をスキップして、2つのファイルをすべて印刷するとどうでしょうか?その後、パイプがソートされた出力のためにソートする:

$ 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 
+0

@EdMorton一般的に、インデックスを作成するときにコンマを使用しないでください。ちょうど '1 23 'のような行があって、' 12 3 'でもかまいませんか?それを防ぐために常に 'FS'を使うのは安全でしょうか? – fedorqui

+1

'12 3'と' 1 23'の問題は、あなたのサブスクリプトの間に何も置かずに、両方が '123'に連結するときに発生します。 '、'、 'FS 'を使うとその問題は解決します。配列のインデックスを表示するときや、インデックスを参照する場所が複数ある場合(例: '{key = $ 1 FS $ 2} [key] ++)には、' FS'(または適切な場合は 'OFS') {map(key)= $ NF; ...} END {for map i}} ')、そうでなければ、簡潔に'、 'を使うべきです。 –

+1

@ EdMortonいつものように大きな助け! – fedorqui

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] 
} 
+0

私はFSが多すぎると言っていました。あなたはただそれを削除しました。いいです!私たちはどちらも同じ出力を持っています。私はあなたがうまく説明してくれたという事実が好きです。 – fedorqui

+2

ええ、私は 'test.awk'とコマンドラインで修正しましたが、投稿されたバージョン... TGIFを忘れました。 –

+0

あなたのNR == FNRと他のブロックは同一なので、2つの別々のブロックは必要ありません。 'NR == FNR {...}'ブロックを取り除くだけで、残っているものは両方のファイルで正常に動作します。 –

関連する問題