はじめに
こんにちは。今日はSQLのポイントについてまとめます。
本文
グループ化
グループ化を行うには、GROUP BY句を使用します。集計を行うときにキーとなる列または列の組みを指定し、キーの値が同じ行をまとめて集計します。
この表に対して、商品ごとの売り上げ数量を知りたいので商品番号ごとに数量を合計するという場合は、次のようなSQL文を記述します。
SELECT 商品番号, SUM(数量) FROM 伝票明細
GROUP BY 商品番号
すると、GROUP BY句で指定した商品番号列をキーとして、同じ商品番号を持つ行の数量を集計します。
図にすると次のようなイメージです。
[例:]
グループ化後に使用できる属性
GROUP BY句でグループ化を行うと、キーとなる列を元に複数の行が1つにまとまります。そのため、グループ化前の列にはアクセスできなくなります。
SELECT文では、GROUP BY句のあとにHAVING句、ORDER BY句を続けることができますが、これらの句は、グループ化後の表に存在する内容しか指定できません。したがって、GROUP BY句を使った場合、HAVING句、ORDER BY句で指定でき、SELECT句の列リストで表示できるのは、グループ化を行った列と、集約関数のみになります。
例えば、商品番号だけでなく、商品名も表示させたい場合を考えます。
-- 構文エラーの例
SELECT 商品番号, 商品名, SUM(数量) FROM 伝票明細
FROUP BY 商品番号
商品名は、グループ化する列でも集計関数でもないので、グループ化後に値を特定できないからです。
そのため、商品名を表示させたい場合は、GROUP BY句に商品名を含め、次のようにします。
-- 例
SELECT 商品番号, 商品名, SUM(数量) FROM 伝票明細
FROUP BY 商品番号, 商品名
SELECT AVG(年齢)
FROM 会員
GROUP BY グループ
HAVING COUNT(*) > 1
このSQL文はグループごとにグループ化し、それぞれのグループの行が1行を超えるものを取り出すSQL文です。
結合
結合には、θ結合、等結合、自然結合、外部結合など様々な種類があります。
主にJOIN句を用います。
例として、次のような表"R"と"S"を考えます。
1. θ結合
θ結合は、任意の演算子で結合する手法です。
-- 例
SELECT * FROM R INNER JOIN S ON R.A > S.A
-- or
SELECT * FROM R, S WHERE R.A > S.A
結果は次のようになります。
[θ結合[R.A>S.A]の演算結果]
2. 等結合
等結合は、演算子θが=になったものです。R.AとS.Aが結合に用いる列の場合、SQL文は次のようになります。
-- 例
SELECT * FROM R INNER JOIN S ON R.A = S.A
-- or
SELECT * FROM R, S WHERE R.A = S.A
結果は次のようになります。
[等結合[R.A=S.A]の演算結果]
3. 自然結合
自然結合では、等結合から重複する列の一方を省略します。R.AとS.Aは同じ内容なので、1つを減らしてAにします。
SQL文では自然結合はよく使うので、いろいろな形式があります。
SELECT R.A, B, C FROM R INNER JOIN S ON R.A = S.A
-- or
SELECT * FROM INNER JOIN S USING A
-- or
SELECT * FROM R NATURAL INNER JOIN S
-- or
SELECT R.A, B, C FROM R, S WHERE R.A = S.A
演算結果はいずれも次のようになります。
[自然結合の演算結果]
4. 外部結合
外部結合では、一方の表に存在しない行も表示します。左外部結合(LEFT OUTER JOIN)、右外部結合(RIGHT OUTER JOIN)、完全外部結合(FULL OUTER JOIN)の3種類あります。一般的には、左外部結合が用いられます。
-- 例
SELECT R.A, B, C FROM R LEFT OUTER JOIN S ON R.A = S.A
-- or
SELECT * FROM R LEFT OUTER JOIN S USING A
-- or
SELECT * FROM R NATURAL LEFT OUTER JOIN S
演算結果はいずれも次のようになります。
[左外部結合の演算結果]
副問合せ
SQL文には入れ子型にSELECT文を入れることができます。そのSELECT文のことを副問合せと呼びます。
-- 例
SELECT 顧客番号, 顧客名 FROM 顧客
WHERE 顧客番号 IN (SELECT 顧客番号
FROM 伝票
WHERE 商品番号 = '2001')
副問合せの外側のSQL文は主問合せと言いますが、実際に最終結果として得られるのは主問合せの内容です。
副問合せは、条件式の中などに記述し、選択条件などを決めるときの参考にします。
副問合せには2種類あります。
- 主問合せと副問合せが相関しない質問
- 主問合せと副問合せが相関する質問(相関副問合せ)
1の場合、演算は単純です。副問合せを先に実行し、その結果を元に主問合せを実行すればいいからです。
2の相関服問合せは、主問合せと副問合せで関連する行や列を扱う場合に行うもので、その処理は少し複雑になります。
-- 例1
SELECT プロジェクト番号, 社員番号 FROM プロジェクト
WHERE 社員番号 IN
(SELECT 社員番号 FROM 社員 WHERE 部門 <= '2000')
相関副問合せ
相関副問合せは、主問合せと副問合せの間の入れ子に関連がある場合の問合せです。このとき、入れ子になったSQL文では、主問合せから1行ずつ値をもらいながら副問い合わせを実行していきます。
-- 例
SELECT プロジェクト番号, 社員番号 FROM プロジェクト
WHERE EXISTS (SELECT * FROM 社員
WHERE 部門 <= '2000'
AND 社員番号 = プロジェクト.社員番号)
これを実行するためには、主問合せで使用する"プロジェクト"表を1行ずつ読み込んで、副問合せに渡す必要があります。
まずは、最初の行('P001', '1111')の値を副問合せに渡します。すると副問合せの内容は次のようになります。
-- 例: TRUE
SELECT * FROM 社員
WHERE 部門 <= '2000'
AND 社員番号 = '1111'
-- 例: FALSE
SELECT * FROM 社員
WHERE 部門 <= '2000'
AND 社員番号 = '3333'
同じように2行目以降も続けていきます。
EXISTS句は、結果が1行異状あるかどうかを確認する句です。相関副問合せでは、他にもSOMEやALLなどを使用することができます。
EXISTSとINの違い
基本的に、EXISTS(存在するかどうかチェック)でも IN(含まれているかどうかチェック)でも同じことができます。また、単純に結合演算で表現することも可能な場合があります。例えば、次の3つのSQL文は、同じ結果を返します。
-- 例1: IN句による副問合せ
SELECT プロジェクト番号, 社員番号 FROM プロジェクト
WHERE 社員番号 IN (SELECT 社員番号 FROM 社員
WHERE 部門 <= '2000')
-- 例2: EXISTS句による相関副問合せ
SELECT プロジェクト番号, 社員番号 FROM プロジェクト
WHERE EXISTS (SELECT 社員番号 FROM 社員
WHERE 部門 <= '2000'
AND 社員番号 = プロジェクト.社員番号)
-- 例3: 結合を使って表現(USING以外でも記述可能)
SELECT プロジェクト番号, 社員.社員番号
FROM プロジェクト INNER JOIN 社員 USING 社員番号
WHERE 部門 <= '2000'
これらのうちどれを使っても構いませんが、DMMSでのテーブルの状況によって、どのSQL文がより高速に処理できるかが変わってきます。一般的に、EXISTSはテーブルの内容を取り出さず、インデックスで存在のみをチェックするだけなので高速なことが多いです。また、NOT EXISTS句など、NOTを入れた否定演算を行う場合には、結合では表現できません。
まとめ
いかがでしょうか?