リレーショナルデータベースのUNIONの実装で条件文のOR演算を実現

データベースの勉強に、かわいいデータベースを実装していたら、だいぶかわいさがなくなってきました。
http://d.hatena.ne.jp/nowokay/20120817#1345197962


ところで、先日、「UNIONの実装はどう?」というコメントに「実際に使わないから乗り気しない」みたいなこと書いたのです。
http://d.hatena.ne.jp/nowokay/20120821#c


実際、SQLでUNIONを使うことは、そこまで多くないと思います。
でも、よく考えると、直接UNIONを使うことはなくても、インデックスが使える条件のORでは、内部的にUNIONが使われることも多いわけです。


ということで、UNION実装してみました。あと、OR演算で面白い結果が出せるように、BETWEENも実装しました。
それと、DISTINCTを実現するために、各タプルにoidをつけるようにしています。


次のようにしてUNIONができます。

System.out.println(Query
        .from("shohin").between("price", 100, 150)
        .union(Query
        .from("shohin").between("price", 250, 300), true));

こんな感じで、「(price between 100 and 150) or (price between 250 and 300)」という条件式での抽出になっています。

 |shohin.shohin_id|shohin.shohin_name|shohin.kubun_id|shohin.price|
 |2|みかん|1|130|
 |5|わかめ|null|250|
 |1|りんご|1|300|

unionメソッドの2番目の引数はDISTINCT指定です。


次のように、条件が重なる場合のUNIONでも、DISTINCT指定のおかげで、重複する行は排除されています。ここでは200円の商品であるキャベツが重複するはずです。

System.out.println(Query
        .from("shohin").between("price", 150, 200)
        .union(Query
        .from("shohin").between("price", 200, 250), true));

こんな感じ。

 |shohin.shohin_id|shohin.shohin_name|shohin.kubun_id|shohin.price|
 |6|しいたけ|4|180|
 |3|キャベツ|2|200|
 |4|さんま|3|220|
 |5|わかめ|null|250|


DISTICNT指定をfalseにすると、重複を排除しません。

System.out.println(Query
        .from("shohin").between("price", 150, 200)
        .union(Query
        .from("shohin").between("price", 200, 250), false));

キャベツが2回でてます。

 |shohin.shohin_id|shohin.shohin_name|shohin.kubun_id|shohin.price|
 |6|しいたけ|4|180|
 |3|キャベツ|2|200|
 |3|キャベツ|2|200|
 |4|さんま|3|220|
 |5|わかめ|null|250|

ただし、DISTINCT指定が有効なのは、テーブルを抽出した場合だけで、JOINした場合には無効です。


あと、いまはoidをSetにつっこんで重複判定をしているのですけど、一旦oidでソートしておいて重複判定するほうがいいかもしれません。


ソースはこちら。
https://gist.github.com/3380142/e65b7a2b6830f20c648e170f80829325e3312c72