RDBは集合、SQLは集合の操作
この記事について
という記事がZennのランキングに載っていて、X (Twitter) 上で感想を書いたところ執筆者の方と少しだけ会話させていただけた。
その中で、わりとDB周りを見る経験があった自分が持っているRDBやSQLへの認識をシェアしておくと、他の方にも参考になるかもしれないと思ったので、この記事で軽くまとめておく。
RDBとSQL
Wikipediaには以下のように書かれている。
関係データベース(かんけいデータベース、リレーショナルデータベース、英: relational database)は、関係モデル(リレーショナルデータモデル、後述)にもとづいて設計、開発されるデータベースである。
関係モデルは、IBMのエドガー・F・コッドが考案し、現在もっとも広く用いられるデータモデルである。データベースの利用者は、クエリ(問い掛け)をデータベースに与え、データを検索したり、変更することができる。
データは表に似た構造で管理されるが、関係(リレーション)と呼ぶ概念でモデル化される。関係(リレーション)は組(タプル、表における行に相当する)、属性(アトリビュート、表における列に相当する)、定義域(ドメイン)、候補キー(主キー)、外部キーなどによって構成される。
はてなんのことやら、という気分になる人が多いだろう。
私の認識としては、RDBは「集合」を管理するものである。
RDBの行は各カラムの元を一つずつ要素に持つ組 (Tuple) の集合であり、その集合を良い感じに結合したり、抽出したりするのがSQLである。
そして、SQLでは集合の部分はカラムの型と数が合っていれば別の集合で置き換えられる。
具体例
例えば、以下のようなusers
テーブルがあるとする。これが意味するのは、「users
集合の元はid
、name
、age
の元をそれぞれ一つずつ持つ組」ということである。
id | name | age |
---|---|---|
1 | Aさん | 5歳 |
2 | Bさん | 10歳 |
3 | Cさん | 15歳 |
4 | Dさん | 20歳 |
5 | Eさん | 25歳 |
この時、以下のようなSQLを実行することで、age
が5歳
以上のユーザーを抽出できる。
SELECT * FROM users WHERE age >= 5;
ここで、5
は正確には「INT型が1個だけ存在する1行だけの集合」であるから、別の「INT型が1個だけ存在する1行だけの集合」で置き換えられる。
例えば、このテーブルの最年少の年齢を取得するSQLと置き換えてみよう。これは年齢が一つだけ返ってくるから、型が合っているので置き換えられる。
SELECT * FROM users WHERE age >= (SELECT MIN(age) FROM users group by id);
これは構文としては正しく、実行するとage
がテーブルの最小値
以上のユーザーを抽出できる。
同様に、例えばusers
テーブルも集合である。こちらもAさんを除外する形で置き換えてみよう。users
の部分は「id
、name
、age
の元をそれぞれ一つずつ持つ組」の集合であるから、id
が1
以外のユーザーを抽出するSQLに置き換えても型が合っているので成り立つ。
SELECT * FROM (SELECT * FROM users WHERE id != 1) WHERE age >= (SELECT MIN(age) FROM users group by id);
これも構文としては正しく、実行するとAさんを除いたテーブルについて、age
がテーブルの最小値
以上のユーザーを抽出でき、最終的にはBさん以降が出力されるはず。
もちろんさらに集合に置き換えて複雑なSQLを作ることもできる。
まとめ
RDBとSQLは集合を扱うものである。
集合の部分は、型と数が合っていれば別の集合で置き換えられる。結局意識すべきは型なのだ。
これを意識してSQLを書くと、よりSQLで書ける世界が広がるかもしれない。
なお今回はクエリのパフォーマンスは一切考慮していない。あくまでサブクエリって自分はこういう認識だよを伝えるためだけの記事です。
Discussion