関係演算とは ― 選択・射影・結合の違い
関係
関係演算とは、表から新しい表を作る操作
関係演算とは、関係データベースの表を入力にして、新しい表を結果として返す操作です。代表的なものに、行を取り出す選択、列を取り出す射影、2つの表をつなぐ結合があります。結果も表なので、ある演算の結果に別の演算を続けてかけられます。
SQLのSELECT文の句の多くは、この演算に当たります。WHERE句は選択、SELECTの直後に並べる列名は射影、JOINは結合です。どの句がどの演算かが分かると、長いSQLも句ごとに分けて読めます。
RDBの表を数学の関係として扱う考え方は、1970年にE. F. Coddが論文で示しました。Coddは1972年の論文で、これらの演算をまとめた体系を関係代数と呼んでいます。選択・射影・結合・商・直積を関係演算、和・差・積を集合演算と分けて呼びます。
| 演算 | する | SQLで |
|---|---|---|
| 選択 | 条件に | WHERE |
| 射影 | 指定した | SELECT DISTINCT 列名 |
| 結合 | 共通の | JOIN |
| 直積 | 2つの | CROSS JOIN |
| 商 | 相手の | 1語では |
| 和 | どちらかの | UNION |
| 差 | 一方の | EXCEPT |
| 積 | 両方の | INTERSECT |
例には、社員表と部署表のような小さな表を使います。SQLの書き方はSELECT文の記事に、表をつなぐ書き方はJOINの記事にまとめました。
選択は行を、射影は列を取り出す
選択は表を横に切り、射影は表を縦に切ります。選択は、部署IDがD1の行のように、条件に合う行だけを残します。射影は、部署IDの列のように、指定した列だけを残します。Coddの1972年の論文では、選択に当たる演算を制限と呼んでいます。
射影の結果では、同じ値の行が1つにまとまります。Coddの論文は、列を選んだあとに行の重複を除いたものを射影と定めています。図の社員表で部署IDの列だけを取り出すと、4行ではなくD1とD2の2行になります。
SQLとの対応では、名前が重なっていることに注意が必要です。条件で行を絞る選択は、WHERE句に当たります。SELECTの直後に列名を並べる部分は、選択ではなく射影に当たります。
SQLのSELECTは、何も指定しないと重複した行も全部残します。関係演算の射影と同じ結果にするには、SELECT DISTINCTと書いて重複を除きます。
結合は共通の列で2つの表をつなぐ
結合は、2つの表に共通する列の値をもとに、行どうしをつないで1つの表にします。社員表と部署表なら、部署IDが等しい行どうしをつなぐと、社員ごとの部署名が分かります。このように列の値が等しいことを条件にする結合を、等結合と呼びます。比べ方を等号に限らず、<や≠なども使えるように広げた結合は、θ結合と呼びます。
等結合の結果には、社員表の部署IDと部署表の部署IDが両方とも残ります。2つの列の値は必ず同じなので、片方は情報として余分です。共通の列を1つにまとめた等結合を、自然結合と呼びます。
| 結合の | 結果の |
|---|---|
| 等結合 | 氏名・ |
| 自然結合 | 氏名・ |
PostgreSQLでは、JOIN ONで条件を書くと両方の表の列がすべて出ます。JOIN USINGやNATURAL JOINで書くと、共通の列は1つにまとまって出ます。一致しない行を残す外部結合は、JOINの記事で説明しています。
直積はすべての組合せ、商はすべてを満たすものを求める
直積は、2つの表の行を条件なしにすべて組み合わせます。4行の社員表と2行の部署表の直積は、4×2=8行です。SQLではCROSS JOINで書きます。
直積の8行のうち、部署IDが一致する行だけを選ぶと、等結合と同じ4行になります。等結合は、直積に選択をかけたものです。図の直積では、この4行に色を付けています。
商は、直積の逆に当たる演算です。割られる表の中から、割る表の値をすべて持つものを求めます。例えば、受講記録を必修研修の表で割ると、必修研修を全部受けた人が分かります。
SQLには、商を1語で書く指定がありません。GROUP BYで人ごとにまとめ、受けた必修研修の数が必修研修の総数と等しい人を残す形で書きます。総数を数える部分には、サブクエリを使います。
和・差・積は、列の並びが同じ表どうしで使う
和・差・積は、2つの表を行の集まりとみなして計算する集合演算です。和はどちらかの表にある行を集め、両方にある行は1行にします。差は一方の表にだけある行を残し、積は両方の表にある行だけを残します。
集合演算は、列の数と、対応する列の型がそろった表どうしでしか使えません。行と行を比べて同じかどうかを決めるので、列の並びが違うと比べられないためです。PostgreSQLの公式ドキュメントも、UNION・INTERSECT・EXCEPTの2つの問合せにこの条件を求めています。この条件を満たす2つの表は、和両立であるといいます。
SQLでは、和をUNION、差をEXCEPT、積をINTERSECTで書きます。どれも重複した行を除き、ALLを付けたときだけ重複を残します。なお、集合演算の積は両方にある行を残す演算で、すべての組合せを作る直積とは別物です。
演算を選んで、入力と結果の表を比べる
次の図で演算を選ぶと、入力の表と結果の表が切り替わります。入力の表で色が付いた行や列は、結果に使う部分です。図は実際のデータベースには接続しておらず、結果はあらかじめ計算した固定の値です。
| 氏名 | 部署ID |
|---|---|
| 田中 | D1 |
| 佐藤 | D2 |
| 鈴木 | D1 |
| 高橋 | D2 |
SELECT * FROM 社員 WHERE 部署ID = 'D1';| 氏名 | 部署ID |
|---|---|
| 田中 | D1 |
| 鈴木 | D1 |
| 氏名 | 部署ID |
|---|---|
| 田中 | D1 |
| 佐藤 | D2 |
| 鈴木 | D1 |
| 高橋 | D2 |
SELECT DISTINCT 部署ID FROM 社員;| 部署ID |
|---|
| D1 |
| D2 |
| 氏名 | 部署ID |
|---|---|
| 田中 | D1 |
| 佐藤 | D2 |
| 鈴木 | D1 |
| 高橋 | D2 |
| 部署ID | 部署名 |
|---|---|
| D1 | 営業部 |
| D2 | 開発部 |
SELECT 氏名, 部署ID, 部署名 FROM 社員
JOIN 部署 USING (部署ID);| 氏名 | 部署ID | 部署名 |
|---|---|---|
| 田中 | D1 | 営業部 |
| 佐藤 | D2 | 開発部 |
| 鈴木 | D1 | 営業部 |
| 高橋 | D2 | 開発部 |
| 氏名 | 部署ID |
|---|---|
| 田中 | D1 |
| 佐藤 | D2 |
| 鈴木 | D1 |
| 高橋 | D2 |
| 部署ID | 部署名 |
|---|---|
| D1 | 営業部 |
| D2 | 開発部 |
SELECT * FROM 社員
CROSS JOIN 部署;| 氏名 | 社員.部署ID | 部署.部署ID | 部署名 |
|---|---|---|---|
| 田中 | D1 | D1 | 営業部 |
| 田中 | D1 | D2 | 開発部 |
| 佐藤 | D2 | D1 | 営業部 |
| 佐藤 | D2 | D2 | 開発部 |
| 鈴木 | D1 | D1 | 営業部 |
| 鈴木 | D1 | D2 | 開発部 |
| 高橋 | D2 | D1 | 営業部 |
| 高橋 | D2 | D2 | 開発部 |
| 氏名 | 研修 |
|---|---|
| 田中 | Excel |
| 田中 | SQL |
| 田中 | セキュリティ |
| 佐藤 | Excel |
| 鈴木 | Excel |
| 鈴木 | セキュリティ |
| 高橋 | SQL |
| 研修 |
|---|
| Excel |
| セキュリティ |
SELECT 氏名 FROM 受講記録
WHERE 研修 IN (
SELECT 研修 FROM 必修研修)
GROUP BY 氏名
HAVING COUNT(*) = (
SELECT COUNT(*) FROM 必修研修);| 氏名 |
|---|
| 田中 |
| 鈴木 |
| 氏名 | 部署ID |
|---|---|
| 田中 | D1 |
| 佐藤 | D2 |
| 鈴木 | D1 |
| 氏名 | 部署ID |
|---|---|
| 田中 | D1 |
| 高橋 | D2 |
SELECT * FROM Excel研修
UNION
SELECT * FROM SQL研修;| 氏名 | 部署ID |
|---|---|
| 田中 | D1 |
| 佐藤 | D2 |
| 鈴木 | D1 |
| 高橋 | D2 |
| 氏名 | 部署ID |
|---|---|
| 田中 | D1 |
| 佐藤 | D2 |
| 鈴木 | D1 |
| 氏名 | 部署ID |
|---|---|
| 田中 | D1 |
| 高橋 | D2 |
SELECT * FROM Excel研修
EXCEPT
SELECT * FROM SQL研修;| 氏名 | 部署ID |
|---|---|
| 佐藤 | D2 |
| 鈴木 | D1 |
| 氏名 | 部署ID |
|---|---|
| 田中 | D1 |
| 佐藤 | D2 |
| 鈴木 | D1 |
| 氏名 | 部署ID |
|---|---|
| 田中 | D1 |
| 高橋 | D2 |
SELECT * FROM Excel研修
INTERSECT
SELECT * FROM SQL研修;| 氏名 | 部署ID |
|---|---|
| 田中 | D1 |
参考にした資料
- E. F. Codd「A Relational Model of Data for Large Shared Data Banks」Communications of the ACM, Vol.13, No.6, 1970 (2.1節。射影の定義と、関係に集合演算を使うときの注意)
- E. F. Codd「Relational Completeness of Data Base Sublanguages」IBM Research Report RJ987, 1972 (2章。関係代数、union-compatible、θ-join、restriction の定義)
- PostgreSQL公式ドキュメント「Table Expressions」(CROSS JOINの行数、JOIN ONとJOIN USING・NATURAL JOINの列の違い、WHERE)
- PostgreSQL公式ドキュメント「Select Lists」(DISTINCTによる重複行の除去)
- PostgreSQL公式ドキュメント「Combining Queries」(UNION・INTERSECT・EXCEPTの意味と、列の数と型がそろう条件)
練習問題(全6問)
正解:射影
列を
正解:選択
WHERE句は
正解:12行
直積は
正解:列の
和・差・積は、
正解:必修研修を
商は、
正解:自然結合は
どちらも
選んでから「採点する」を押すと、解説つきで答え合わせができます。
関連記事
おすすめの本 PR
セキュリティとデータベースは、基本情報技術者試験の対策本でまとめて学べます。

