「ゼロからはじめるデータベース操作」を読んで --- SQL操作を整理(第三章、四章)

投稿者: MUTA-dev投稿日: 2025年10月20日更新日: 2025年10月21日
カテゴリ:TechBook
タグ:DBSQLPostgreSQL

本記事は、「ゼロからはじめるデータベース操作」を読んで --- SQL操作を整理(第一章、二章) の続きです。

集約と並び替え

テーブルを集約して検索する

SQLでデータに対して操作や計算を行うには、「関数」を使います。関数には以下のようなものがあります。

  • COUNT : テーブルのレコード数(行数)を数える
  • SUM : テーブルの数値列のデータを合計する
  • AVG : テーブルの数値列を平均する
  • MAX : テーブルの任意の列のデータの最大値を求める
  • MIN : テーブルの任意の列のデータの最小値を求める

このような集計用の関数を、「集約関数」や「集合関数」と呼びます。以下に使用例を示します。

SELECT COUNT(*)
  FROM my_table

()中は、引数になります。*という記号はNULLを含めたテーブルの全行を数えるためのものです。NULLを除外したい場合は、対象とする列を限定して引数に書きます。集約関数は、基本NULLを除外しますが、COUNT(*)は例外でNULLを除外しないことに注意が必要です。

SUM関数は、列の合計を求める関数です。NULLは無視して計算してくれます。

AVG関数は、列の平均値を求めます。この関数もNULLを無視して計算してくれます。

複数行の中から、最大値、最小値を求めるには、それぞれMAXとMIN関数を使用します。以下が使用例です。

SELECT MAX(cost), MIN(cost)
  FROM products;

重複値を除外して集約関数を使用するには、DISTINCTキーワードを使います。以下に例を示します。

SELECT COUNT(DISTINCT category)
  FROM priducts;

テーブルをグループに切り分ける

テーブルを何かしらの要素によってグループ分けするには、GROUP BY句を使用します。例えば、カテゴリーごとの行数を数えたければ、以下のようにします。

SELECT category, COUNT(*)
  FROM products
 GROUP BY category;

このようにすることで、カテゴリーごとの行数が表示されます。GROUP BY句に指定する列のことを集約キーグループ化列と呼びます。また、集約キーにNULLが含まれていた場合、NULLというグループに分類されます。

GROUP BY句を使用するSELECT文でも、WHERE句を併用できますが、句の記述順に注意が必要です。

SELECT price, COUNT(*)
  FROM products
 WHERE category = 'book'
 GROUP BY price;

FROM->WHERE->GROUP BY->SELECTの順で実行されます。

集約関数を使うときは、次の三つしかSELECT句に書くことが出来ません。

  • 定数
  • 集約関数
  • GROUP BY句で指定した列名(集約キー)

つまり、以下のようなSELECT文はエラーになります。

SELECT name, price, COUNT(*)
  FROM products
 GROUP BY price;

nameという列がGROUP BY句にありません。また、GROUP BY句に列の別名は書けません。

SELECT category AS c, COUNT(*)
  FROM products
 GROUP BY c

このSQL文が実行できないのは、SELECT句よりもGROUP BY句の方が先に実行されるからです。

他のよくある間違いは、WHERE句に集約関数を書くことです。集約関数が書けるのは、SELECT句とHAVING句とORDER BY句だけです。

集約した結果に条件を指定する

WHERE句はレコード(行)に対しての条件指定でしたが、グループに対する条件指定にはHAVING句を使用します。HAVING句はGROUP BY句の後ろに書く必要があります。以下のように使用します。

SELECT category, COUNT(*)
  FROM products
 GROUP BY category
HAVING COUNT(*) = 2;

これは、categoryで集約したグループから、含まれる行数が2行のものを選択しています。

HAVING句に書くことのできる要素は、GROUP BY句を使った時のSELECT句と同じで、次の3つになります。

  • 定数
  • 集約関数
  • GROUP BY句で指定した列名(集約キー) よって以下のSQL文は、エラーになります。
SELECT category, COUNT(*)
FROM products
GROUP BY category
HAVING name = 'book';

nameという列はGROUP BY句に含まれていません。

集約キーに対する条件は、WHERE句にもHAVING句にも書くことが出来ます。返す結果も同じです。しかし、WHERE句は行に対する条件指定、HAVING句はグループに対する条件指定なので、集約キーに対する条件はWHERE句に書くべきです。

検索結果を並べ替える

テーブルからデータを選択する際、行の順序を指定するには、SELECT文の文末にORDER BY句を付けます。ORDER句、SELECT文の最後に書きます。また、ORDER句に書く列名を「ソートキー」と呼びます。ORDER BY句は並び順を指定しない場合は暗黙的に昇順になっていますが、降順にしたい場合は列名の後ろにDESCキーワードを使用します。

ORDER BY句には、複数のソートキーを指定することができ、左側のキーから優先的に使用され、そのキーで同じ値が存在した場合に、右側のキーが参照されます。

NULLを含む列をソートキーに指定した場合、NULLは先頭または末尾にまとめて表示されます。

GROUP BY句では、列の別名を使えませんでしたが、ORDER BY句では使えます。それは、SELECT句よりORDER BY句の方が後に実行されるからです。

ORDER BY句には、テーブルに存在する列であれば、SELECT句に含まれていない列でも指定できます。

データの更新

テーブルにデータ(行)を登録するには、INSERT文を使用します。基本構文は以下の通りです。

INSERT INTO <テーブル名> (列1, 列2, 列3, ・・・) VALUES (値1, 値2, 値3, ・・・)

具体例を以下に示します。

INSERT INTO my_table (id, name, category, price) VALUES ('0001', 'pasta', 'food', 1200);

上記で示した、(id, name, category, price)の部分を列リスト、('0001', 'pasta', 'food', 1200)の部分を値リストと呼びます。 原則として、INSERT文は1回で1行を挿入するようにします。

テーブルの全列に対してINSERTを行う場合、列リストは省略することが出来ます。また、ある列にNULLを割り当てたい場合は、VALUES句の値リストにNULLをそのまま記述します。

列にデフォルト値を設定するには、CREATE TABLE文で、列に対してDEFAULT制約を付けます。以下に例を示します。

CREATE TABLE my_table
(id    CHAR(4)    NOT NULL,
price  INTEGER    DEFAULT 0,
ORIMARY KEY (id));

DEFAULTを設定した列は、INSERT文を使用する際、VALUES句にDEFAULTキーワードを指定するか、DEFAULTを設定した列を列リストとVALUESからも省略することでデフォルト値を挿入することが出来ます。つまり、以下の二通りで実装できます。

INSERT INTO my_table (id, price) VALUES ('0001', DEFAULT);
INSERT INTO my_table (id) VALUES ('0001');

(続きを執筆中・・・)

参考文献:

  • ミック. SQL 第2版 ゼロからはじめるデータベース操作. 翔泳社. Kindle 版.