スキーマはこちら。型をかなり省略しています。いわゆるToxi法(中間テーブルがある)ってやつです。
create table article ( id integer primary key, ... ); create table article_tag_rel ( article_id, tag_id, ... ); create table tag ( id integer primary key, name, ... );
どうやって書きますか? 私はこう書きました。
select distinct a.* from article a left join article_tag_rel atr on a.id = atr.article_id left join tag t on atr.tag_id = t.id where t.id is null or t.name not in ('dame', 'desu', ...) order by a.id desc limit N;
- タグがない記事は
t.id is null
になるので表示される - タグがあるならNGタグが付いてないか確認してから表示する
という処理が行われています。記事に対して必ず1個以上のタグがあるならぜんぶ inner join でいい気もする。
SQLだけでやろうとしてこうなっているけど、実用的にはアプリケーションでうまく計算してキャッシュしたりマテリアライズドビュー使ったりするほうがよさそう? このへんどういう実装にすることが多いのか事例を知りたい。
最初はleft joinが3つあったけど、2つでいいじゃんということになった。