ウェブエンジニア問題集
第2章

SELECTの基本 — 列指定・別名・DISTINCTを理解する

6
この章の目次開く

SQLで最初に覚えるべき構文は SELECT です。 SELECT は、テーブルから必要な列を取り出すために使います。

この章では、列の指定、すべての列の取得、別名、重複除去、式の利用まで、SELECT の基本を整理します。

学習者学習者

SELECT * なら全部取れるから、それだけ覚えればよさそうに見えるけど、実務でもそれでいいの?

SELECTの最小形

基本形は次の通りです。

SELECT 列名
FROM テーブル名;
sql

たとえば、users テーブルからユーザー名を取得するならこう書きます。

SELECT name
FROM users;
sql

複数の列を取りたい場合は、カンマで区切ります。

SELECT name, email, created_at
FROM users;
sql
SELECT には「取り出したい列」を書き、FROM には「対象のテーブル」を書きます。

すべての列を取得する

* を使うと、すべての列を取得できます。

SELECT *
FROM users;
sql

学習中や調査中には便利ですが、アプリケーションコードでは使いすぎに注意します。

SELECT * には次の弱点があります。

  • 不要な列まで取得して通信量が増える
  • テーブルに列が追加されたとき、意図せず取得結果が変わる
  • どの列を使っているのかSQLだけでは分かりにくい
  • インデックスだけで完結する検索の機会を逃すことがある
先生先生

SELECT * は中身を確認するときは便利だけど、本番コードでは必要な列だけ書こう。通信量も減るし、何を使ってるかが一目で分かる。

列に別名を付ける

AS を使うと、取得結果の列名に別名を付けられます。

SELECT
  name AS user_name,
  email AS email_address
FROM users;
sql

集計結果や式の結果には、別名を付けると読みやすくなります。

SELECT
  price * quantity AS subtotal
FROM order_items;
sql

AS は省略できるDBMSも多いですが、学習中は書いた方が意図が明確です。

-- ASあり
SELECT name AS user_name FROM users;
 
-- ASなし
SELECT name user_name FROM users;
sql
別名は、SQLの結果をアプリケーション側で扱いやすい名前に整えるために使います。

DISTINCTで重複を除く

DISTINCT を使うと、重複した行を1つにまとめられます。

SELECT DISTINCT prefecture
FROM users;
sql

このSQLは、ユーザーが登録している都道府県の一覧を重複なしで返します。

複数列に DISTINCT を使う場合は、列の組み合わせ全体で重複判定されます。

SELECT DISTINCT prefecture, city
FROM users;
sql

この場合、prefecture だけでなく prefecture + city の組み合わせが同じ行だけが重複として扱われます。

学習者学習者

DISTINCTってJOINの後に重複が出たときにとりあえず付ければいいの?

先生先生

それは危険。DISTINCTで消す前に、なぜ重複しているのかを先に調べよう。JOIN条件のミスが原因なら、DISTINCTで隠すとデータ数がおかしくなるよ。

SELECTで必要なデータだけを正確に取り出すことが、効率的なクエリの第一歩です

式をSELECTする

SELECT には列名だけでなく、計算式や関数も書けます。

SELECT
  price,
  quantity,
  price * quantity AS subtotal
FROM order_items;
sql

文字列を加工したり、日付から一部を取り出したりすることもあります。 関数の名前や書き方はDBMSごとに違う場合があります。

-- PostgreSQLの例
SELECT
  email,
  lower(email) AS normalized_email
FROM users;
sql

SQLで加工すると、アプリケーション側の処理を減らせます。 一方で、複雑すぎる加工をSQLに詰め込むと読みづらくなるため、どちらに寄せるかはチームで判断します。

コメントを書く

SQLにはコメントを書けます。 調査用SQLや複雑なクエリでは、意図を残しておくと後から読みやすくなります。

-- 有効なユーザーだけを取得
SELECT name, email
FROM users
WHERE is_active = true;
sql

複数行コメントも使えます。

/*
  月次レポート用の集計。
  退会済みユーザーは除外する。
*/
SELECT id, name
FROM users
WHERE deleted_at IS NULL;
sql

よくあるハマりどころ

SELECTの順番で実行されると思ってしまう

SQLは上から順に実行されるプログラムではありません。 たとえば WHERE は、SELECT で付けた別名を参照できないことがあります。

-- DBMSによってはエラーになる
SELECT price * quantity AS subtotal
FROM order_items
WHERE subtotal >= 1000;
sql

このような場合は、式を WHERE にも書くか、サブクエリを使います。

SELECT price * quantity AS subtotal
FROM order_items
WHERE price * quantity >= 1000;
sql

SELECT * をAPIの戻り値に使う

APIの実装で SELECT * を使うと、後でテーブルに内部用カラムを追加したときに、そのカラムまで返してしまう可能性があります。

-- 避けたい
SELECT *
FROM users;
 
-- 必要な列だけ返す
SELECT id, name, email
FROM users;
sql

ちゃんと使うためのポイント

  • SELECT には取得したい列を書く
  • FROM には対象テーブルを書く
  • SELECT * は調査には便利だが、本番コードでは必要な列を明示する
  • AS で結果の列名を扱いやすくできる
  • DISTINCT は列の組み合わせ全体で重複を判定する

次の章では、WHEREORDER BYLIMITNULL を使って、取得する行を絞り込む方法を学びます。

SQLクイズに挑戦するこの章で学んだSQLの知識を、4択クイズでアウトプットして定着させよう