unixでRDBのテーブル結合のように複数のファイルを共通のフィールドで結合する場合はjoinコマンドを使う。
上記の例の場合、両ファイル共にフィールド1で結合される。
※ファイルはあらかじめ、結合フィールドでソートされている必要がある。
しかし、joinはそれぞれのファイルに対して、結合フィールドとして1つのフィールドしか指定できない。
上記の例の場合、itemsとshopsで日付が異なるものが結合されてしまっている。
本当はフィールド1とフィールド2の両方で結合したいだろう。
こんな場合はどうすればいいのだろうか。
複数のキーの文字列長が固定でない場合を考慮すると、そのまま文字列結合するのではなく、登場しない文字をセパレータにして文字列結合したほうがいいだろう。
また、joinが要求するソート条件を満たすように文字列結合後にソートしておこう。
こうして作成したファイルの1フィールド目を結合条件として、joinすればいい。
出力フィールドも必要なもののみに絞ると、以下のようになる。
プロセス置換を使えば、一時ファイルを使う必要がなくなるけど、この場合はシェバンをshではなく、bashにする必要がある。
簡単な例
$ cat items 1001 2017-10-08 バナナ 100 1001 2017-10-09 バナナ 90 1002 2017-10-08 りんご 150 1002 2017-10-09 りんご 200 1003 2017-10-08 みかん 80 $ cat shops 1001 2017-10-08 蒲田 1001 2017-10-09 蒲田 1002 2017-10-08 横浜 1002 2017-10-09 横浜 1003 2017-10-08 品川 $ join -11 -21 items shops 1001 2017-10-08 バナナ 100 2017-10-08 蒲田 1001 2017-10-08 バナナ 100 2017-10-09 蒲田 1001 2017-10-09 バナナ 90 2017-10-08 蒲田 1001 2017-10-09 バナナ 90 2017-10-09 蒲田 1002 2017-10-08 りんご 150 2017-10-08 横浜 1002 2017-10-08 りんご 150 2017-10-09 横浜 1002 2017-10-09 りんご 200 2017-10-08 横浜 1002 2017-10-09 りんご 200 2017-10-09 横浜 1003 2017-10-08 みかん 80 2017-10-08 品川
上記の例の場合、両ファイル共にフィールド1で結合される。
※ファイルはあらかじめ、結合フィールドでソートされている必要がある。
しかし、joinはそれぞれのファイルに対して、結合フィールドとして1つのフィールドしか指定できない。
上記の例の場合、itemsとshopsで日付が異なるものが結合されてしまっている。
本当はフィールド1とフィールド2の両方で結合したいだろう。
こんな場合はどうすればいいのだろうか。
複数フィールドで結合
こんな時は結合条件にしたいフィールドのみを文字列結合して、1つのフィールドにしてしまえばいい。$ awk '{ print $1 ":" $2, $1, $2, $3, $4 }' items | sort -k1 >items_with_key $ cat items_with_key 1001:2017-10-08 1001 2017-10-08 バナナ 100 1001:2017-10-09 1001 2017-10-09 バナナ 90 1002:2017-10-08 1002 2017-10-08 りんご 150 1002:2017-10-09 1002 2017-10-09 りんご 200 1003:2017-10-08 1003 2017-10-08 みかん 80 $ awk '{ print $1 ":" $2, $1, $2, $3 }' shops | sort -k1 >shops_with_key $ cat shops_with_key 1001:2017-10-08 1001 2017-10-08 蒲田 1001:2017-10-09 1001 2017-10-09 蒲田 1002:2017-10-08 1002 2017-10-08 横浜 1002:2017-10-09 1002 2017-10-09 横浜 1003:2017-10-08 1003 2017-10-08 品川
複数のキーの文字列長が固定でない場合を考慮すると、そのまま文字列結合するのではなく、登場しない文字をセパレータにして文字列結合したほうがいいだろう。
また、joinが要求するソート条件を満たすように文字列結合後にソートしておこう。
こうして作成したファイルの1フィールド目を結合条件として、joinすればいい。
出力フィールドも必要なもののみに絞ると、以下のようになる。
$ join -11 -21 -o1.2,1.3,1.4,2.4 items_with_key shops_with_key 1001 2017-10-08 バナナ 蒲田 1001 2017-10-09 バナナ 蒲田 1002 2017-10-08 りんご 横浜 1002 2017-10-09 りんご 横浜 1003 2017-10-08 みかん 品川
スクリプトにまとめると
以上をまとめると、こんなスクリプトになる。プロセス置換を使えば、一時ファイルを使う必要がなくなるけど、この場合はシェバンをshではなく、bashにする必要がある。
#!/bin/bash join -11 -21 -o1.2,1.3,1.4,2.4 \ <(awk '{ print $1 ":" $2, $1, $2, $3, $4 }' items | sort -k1) \ <(awk '{ print $1 ":" $2, $1, $2, $3 }' shops | sort -k1)
0 件のコメント:
コメントを投稿