ABOUT

イベント・勉強会

Tech LION

USP Magazine

外部サイト

Twitter

 前へ
 次へ
投稿者: USPMAG編集長   2012年04月04日 20:05    タグ: bash Tukubai OSC

UNIXはシェル上でJOINができる。せっかくあるのに使わないの?

こんにちは、ふたたびUSP MAGAZINE編集長のまつうらです。昨日は風が炸裂してましたけど、爆弾低気圧って呼ぶんですね。ニュースの題名を見た時は「テロでも起こったか!?」とびっくりしました。

さて、その1その2に続き、OSC 2012 Tokyo/Springでのセッションの続きとするつもりだったのですが、書いているうちにだいぶその中で語られていたネタから逸脱してしまったので、フツーに行きます。でも、その2で語らなかったJOINの話です。

INNER JOINがUNIXコマンドでできるの知らなイカ?

INNER JOIN(内部結合)といえば、SQLをかじったりすれば必ず登場する概念。そのINNER JOINをするコマンドが古くからUNIXに存在する(POSIX標準である)のを知っていますか? ―「知らない」 じゃあ、UNIX系OSのターミナル用意して試してみましょう。

まずは、会員番号とそれに対する名前を紐付けたファイルとして次のようなもの(members.txt)を用意しておきます。

1 aaaさん
2 bbbさん
3 cccさん
4 dddさん
5 eeeさん
それから、その会員がいくら購入したかを記録しているポイント表(points.txt)も用意しておきます。ただし、会員番号4のdddさんはポイント未獲得ということにして、記録(dddさん用の行)がまだ存在しないようにしておきましょう。
1 10ポイント
2 20ポイント
3 30ポイント
5 50ポイント
ここまでできたら、あとはこことかこことかに書いてあるjoinコマンドの使い方を見ながら「名前に対応するポイント」を作成してみましょう。
	$ join -1 1 -2 1 members.txt points.txt
	1 aaaさん 10ポイント         # [↑注]
	2 bbbさん 20ポイント         # 左表(-1)の1列目と、右表(-2)の1列目を
	3 cccさん 30ポイント         # キーとする
	5 eeeさん 50ポイント
とご覧の通りなわけですよ(会員番号が邪魔ならさらにパイプでAWKに渡し、2列目,3列目だけ表示させればよい)。一方、ポイント表に未登録な人が誰なのか(すなわちdddさん)を知りたいならば、"-v 1"という具合にオプションを付ければ出てきます。
	$ join -1 1 -2 1 -v 1 members.txt points.txt
	4 dddさん         # [↑注]"-v"オプションで左表(1)にしか無かった行を表示
これの右隣に"0ポイント"と追記して(AWKコマンドを使えば簡単)、最初のjoinコマンドの出力結果とくっつければ(SQL的に言うならUNION)、LEFT JOIN相当のことだってできてしまいます。こうして見ると、USP研究所が考案するまでもなくUNIXシェルは、テキストファイルでリレーショナルデータベース処理をやることを想定していたことがわかります。joinコマンドの存在がその証拠です。さらに勘を働かせば、UNIX自体それに向くような設計になっていると気づくことでしょう。

Tukubaiなら、LEFT JOINも一行で書ける

ということで、UNIXは既にJOINの機能を持っています。でもご覧の通りOpen usp TukubaiはJOIN系のコマンドを5つ(後述の表1)もわざわざ独自に提供しています。なぜ作り直したかということは後回しにして、さっそくやってみましょう。最初のJOINの例と同じく、まずはポイント表に登録されている人だけ表示してみます。

	$ join1 key=1 members.txt points.txt
	1 aaaさん 10ポイント        # [↑注]
	2 bbbさん 20ポイント        # keyは、右表で見る列番号を示す。
	3 cccさん 30ポイント        # (左表に関しては1列目固定)
	5 eeeさん 50ポイント
では次に、ポイント登録の無いdddさんも含まれるようにするにはというと、こんなふうに書きます。
	$ loopj "-d0ポイント" num=1 members.txt points.txt
	1 aaaさん 10ポイント  # [注1]loopjコマンドはFULL JOIN(完全外部結合)に相当
	2 bbbさん 20ポイント  # [注2]"-d"で始まるオプションで文字列を指定すると
	3 cccさん 30ポイント  #      行が存在しなかった表にその文字列が埋込まれる。
	4 dddさん 0ポイント   # [注3]numオプションは、各表の1列目から何列目までを
	5 eeeさん 50ポイント  #      結合用に見るかを指定する(「何列目を」ではない)
こうして、元のjoinコマンドでは簡素に書けなかったLEFT JOIN相当の処理が1行で書けるようになるのです。

ここでTukubaiが提供するJOIN系コマンドをまとめておきます。

表1. TukubaiのJOIN系コマンド一覧
機能 Tukubaiコマンド名
INNER JOIN
(内部結合)
join1(またはjoin0)
LEFT JOIN
(左外部結合)
なし(FULL JOIN相当のloopjで代用するか、
表を左右に入れ替えてRIGHT JOIN相当のjoin2で代用)
RIGHT JOIN
(右外部結合)
join2
FULL JOIN
(完全外部結合)
loopj
直交表作成 loopx

TukubaiのJOIN系コマンドは、高機能化vs単純記述というジレンマ解決のために生まれた

これらTukubaiのコマンドを見てると、きっと鼻につくことがあるでしょう。

  • なぜ左表の結合キーは1列目固定なのか
  • なぜLEFT JOINは無いのか
  • なぜFULL JOINの結合キー指定は、「n列目」ではなく「1~n列目」なのか
などなど。きっと抱く印象は「指定方法に歯抜けが多い」といったところだろうと思います。しかし、これは敢えてそうしたのです。つまり「潔い削ぎ落とし」です。

元々のjoinコマンドは、オプションを駆使すれば確かにいろいろなことが出来ます。オプションだけでできなくても(例えば前述のLEFT JOIN)、コマンドを複数回使えば一応はできます。でも、使用頻度の高い処理が簡素に書けなければ使ってられないわけです。

  • 簡素に書きたい
  • でも必要なことはできないと困る
実際の開発をこなしていると、こういうジレンマが生まれます。ところが開発をこなしてくると、一方で「定番のパターン」というのが見えてくるのです。例えば、「結合する表の殆どは結合キーが左1列目にある」「複数ある場合は1列目から連続している」など。逆に言うと、「一番右の列」とか「奇数列を全部」などということはまず無いのです。そういう極稀なケースに対応するためにオプションで完璧を目指そうとするから書式やコードが複雑になるわけで、潔く対応をやめてしまえば簡単に書けてしまうのです。そういう複雑なケースが仮にあるとしたら、別のコマンド(self等)で列順を都合よく変えておいてから使えばいいだけの話でもあります。

Tukubaiというコマンドセットが提供する機能は、一見歯抜けに見えますが、実際使ってみると9割、いや、それ以上の割合でその使い方に収まります。なにせTukubaiは、そういうことを試行錯誤しながら仕様を洗練させていったのですから。きっと、使い出したら中毒になりますよ。:-)

↓押してね!

フリーワード検索

新着情報

タグ

人気ページ 2012年2月18日~