SQL プログラミング

【WHEREの基本】細かな条件でデータを取得しよう

スポンサーリンク

SQLec02

頼れる人
データを毎回全部取得してその中から自分で欲しいデータだけを選ぶのはすごく面倒なことです
欲しいデータだけを取得するにはどうすればいいのか?簡単な条件からちょっと手の込んだ条件をどうやって指定すればいいのかも教えるよ

指定できる条件には、基本的なものから複雑なものまでさまざまな方法があるんだよ
簡単な条件を指定する方法は前回でも触れたけど、ここだけ読めば条件指定の基本がわかるようになるよ
ぴよちゃん

もうすでにWHERE句を使った条件指定の方法は知ってるよ!という人は、ここは読まなくていいですよ
こけさん

欲しいデータだけを取得しよう(WHERE句)

DataBase_arrow2

テーブルの中からほしいデータだけを取得するには「WHERE句」を使います。

WHEREのあとに、絞り込みしたいカラム名と条件を指定します。
社員テーブルからIDが1と等しいデータを取得するには、このように書きます。〇〇と△△が等しいという条件を作成するときには、イコール(=)を使います。

// 社員テーブルからIDが1のレコードを取得
SELECT *
FROM employee
WHERE id = 1;

〇〇以上や〇〇未満でデータを取得するには…

〇〇と△△が等しいという条件を作成するときには、イコール(=)を使いました。
〇〇より大きい△△という条件のときには、>を使います。また、〇〇が△△以上という条件のときは、>と=を使います。
逆に〇〇より小さい△△という条件のときには、<を使います。〇〇が△△以下という条件のときは、<と=を使います。
このような、より大きいとかより小さいといった大小比較をするときは、数値型のカラムや日付型のカラムで利用するケースとなります。

// 社員テーブルからIDが10以上のレコードを取得
SELECT *
FROM employee
WHERE id >= 10;
// 社員テーブルから誕生日 [birthday] が2000/1/1より前のレコードを取得
SELECT *
FROM employee
WHERE birthday < '2000-01-01';

〇〇ではないデータを取得するには(NOT)

〇〇が△△ではないという否定条件とするときには、先ほどの条件式の前にNOTを付けます。
〇〇と△△が等しくないという否定条件のときは、NOTの代わりに<>でも構いません。

// 社員テーブルから性別 [sex] が1(男性)以外のレコードを取得
SELECT *
FROM employee
WHERE NOT sex = 1;
// 社員テーブルから性別 [sex] が1(男性)以外のレコードを取得
SELECT *
FROM employee
WHERE sex <> 1;

文字列型や日付型のときは値の前後にシングルコーテーション(’ )を付けます。数値型のときは付けないようにします。

複数の条件を指定するには(AND・OR)

両方の条件に一致させるには(AND)

複数の条件を指定したあと、それらの条件をANDで結び付けます。
ANDで結び付ける条件の数には上限はありません。

// 社員テーブルから性別 [sex] が1(男性)かつ、誕生日 [birthday] が2001/1/1以降のレコードを取得
SELECT *
FROM employee
WHERE sex = 1
AND birthday >= '2001-01-01';

どちらかだけの条件に一致させるには(OR)

複数の条件を指定したあと、それらの条件をORで結び付けます。
ORで結び付ける条件の数には上限はありません。

// 社員テーブルから性別 [sex] が2(女性)または、誕生日 [birthday] が2001/1/1以降のレコードを取得
SELECT *
FROM employee
WHERE sex = 2
OR birthday >= '2001-01-01';

AND条件とOR条件を混在させるには

場合によっては、いくつもの条件をANDやORで結び付けるケースが出てきます。
SQLではWHERE句に書かれた順に条件判定がされますので、この条件とこの条件とはANDで結び付ける、この条件とこの条件とはORで結び付けるということを明確に指定する必要があります。
そのため、以下のように単純にANDとORでそれぞれを結びつけるような書き方をしてはいけません。

// 社員テーブルから性別 [sex] が1(男性)または
// 性別 [sex] が2(女性)かつ所属部署 [dept] が経理部のレコードを取得
SELECT *
FROM employee
WHERE sex = 1
OR sex = 2
AND dept = '経理部';

上のSQLは一見すると正しいようにも見えます。
男性社員全員 と 女性社員で経理部に所属 のレコードを取得したいのに、このSQLだと上から順番に条件判定されてしまうため、男性社員・女性社員の中で経理部に所属のレコードしか取得できません。

では、どのように指定すればいいのかというと、関連する条件の前後にカッコを付けます
算数と同様にカッコを付けると、その中を優先的に条件判定してくれます。

// 社員テーブルから性別 [sex] が1(男性)または
// 性別 [sex] が2(女性)かつ所属部署 [dept] が経理部のレコードを取得
SELECT *
FROM employee
WHERE sex = 1
OR (sex = 2 AND dept = '経理部');

このように、女性社員で経理部所属の条件に合ったレコード と 男性社員のレコードを取得することができます。
ANDやORが複雑に絡み合うケースもありますので、うまくカッコを使ってどの条件を優先的に判断させるのかを正しく指定しましょう。
ANDとORを混在する条件を指定してしまうと、予期せぬ結果となりますので、そのときにはカッコを付けた位置が正しいかをよく確認しましょう。

一部の値だけを一致させたいときは(LIKE)

指定した値がカラムの先頭と一致するレコードを取得するには(前方一致検索)

名前が「山田」で始まるレコードを取得したいときには、LIKEを使います。
等しい場合には「= '山田'」と書きますが、山田で始まるレコードを取得したいときには、山田の後ろにパーセント(%)を付けます。
%を付けることで、山田で始まっていればそのあとはどんな文字でも条件にヒットします。もちろん山田のみの場合でも条件にヒットします。

LIKE検索は文字列型のカラムに用います。

// 社員テーブルから名前 [name] が山田で始まるレコードを取得
SELECT *
FROM employee
WHERE name like '山田%';

// OK 山田太郎
// NG 山之上次郎
// NG 岡山花子

指定した値がカラムの一部に含まれるレコードを取得するには(部分一致検索・中間一致検索)

名前に「川」を含むレコードを取得したいときには、川の前後にパーセント(%)を付けます。
前方一致検索と同じように、川の前後に文字があってもなくても条件にヒットします。

// 社員テーブルから名前 [name] に川を含むレコードを取得
SELECT *
FROM employee
WHERE name like '%川%';

// NG 山田太郎
// OK 山川次郎
// NG 岡山花子

指定した値がカラムの最後と一致するレコードを取得するには(後方一致検索)

名前が「子」で終わるレコードを取得したいときには、子の前にパーセント(%)を付けます。
前方一致検索と同じように、子の前に文字があってもなくても条件にヒットします。

// 社員テーブルから名前 [name] が子で終わるレコードを取得
SELECT *
FROM employee
WHERE name like '%子';

// NG 山田太郎
// NG 山之上次郎
// OK 岡山花子

ワイルドカードとは…

前方一致検索や部分一致検索といったLIKEを用いて検索を行うときに利用する記号をワイルドカードと言います。
すでにLIKE検索のときに説明しましたパーセント(%)がワイルドカードとなります。

ワイルドカードはパーセント(%)のほかに、アンダースコア(_)があります。
% ・・・ 0文字以上の任意の文字列
_ ・・・ 任意の1文字

%を使ったLIKE検索では、%のところには文字があってもなくても条件にヒットします。
例えば、name LIKE '山%' としたときには、山で始まる名前のレコードがヒットしますが、「山」だけのレコードもヒットします。

// 社員テーブルから名前 [name] が山で始まるレコードを取得
SELECT *
FROM employee
WHERE name like '山%';

// OK 山田太郎
// OK 山之上次郎
// NG 岡山花子

_を使ったLIKE検索では、_にはどんな文字でも_のところに1文字入っていれば条件にヒットします。
例えば、name LIKE '山_' としたときには、「山田」や「山下」はヒットしますが、「山之上」はヒットしません。
_を2つつなげて name LIKE '山__' としたときには、「山之上」はヒットしますが、「山田」や「山下」はヒットしません。

// 社員テーブルから名前 [name] が山で始まり、そのあとに1文字あるレコードを取得
SELECT *
FROM employee
WHERE name like '山_';

// OK 山田
// NG 山之上
// NG 岡山
// 社員テーブルから名前 [name] が山で始まり、そのあとに2文字あるレコードを取得
SELECT *
FROM employee
WHERE name like '山__';

// NG 山田
// OK 山之上
// NG 岡山

パーセント(%)とアンダースコア(_)を組み合わせて使うこともできます。

// 社員テーブルから名前 [name] が〇山で始まり、子で終わるレコードを取得
SELECT *
FROM employee
WHERE name like '_山%子';

// NG 山田太郎
// NG 山之上次郎
// OK 岡山花子

ワイルドカード(%や_)の文字で検索したいときは…(ESCAPE)

「生クリーム(乳脂肪分20%)北海道産」のような商品があったとき、「20%」の付く商品だけを取得したいときにはどう書きますか?
これまでのように、product_name LIKE '20%' と書いてしまうと、「20%」を含む商品名はもちろんのこと、「生クリーム(乳脂肪分15%)2000ml」という商品もヒットしてしまいます。

では、このワイルドカードとして使われている文字(%と_)を検索条件として使いたいときにはどのようにしたらよいでしょうか?
ESCAPEを使って「%はワイルドカードとしてではなく、文字列として使います」というのを指定します。
ESCAPEで指定した文字の次の文字だけは、文字列として扱うことを意味します。

エスケープ文字として指定するのは一般的には「\」がよく利用されます。「\」自体を検索条件に使いたいときには、別の文字をESCAPEに指定します。

// 商品テーブルから商品名 [product_name] に20%を含むレコードを取得
SELECT *
FROM product
WHERE product_name like '%20\%%' ESCAPE '\';

シングルコーテーション(’ )の文字で検索したいときには…

文字列型のカラムを条件指定するときには、検索する値をシングルコーテーション(’ )を付けるようにお伝えしました。
では、シングルコーテーションを含む「20's」で検索したいときには、どう書きますか?
product_name LIKE '%20's%' と書いてしまうと、シングルコーテーションの数が合わないためSQLエラーとなってしまいます。

シングルコーテーションを検索文字として使用したいときには、2つ続けて書きます

// 商品テーブルから商品名 [product_name] に20'sを含むレコードを取得
SELECT *
FROM product
WHERE product_name like '%20''s%';

範囲指定するには(BETWEEN)

BETWEENで指定する場合

IDが100番から199番までの100番台を検索したい場合、IDが100以上 かつ IDが200未満のように、2つの条件をANDでつなげて検索することで取得できます。
BETWEENを使っても同じように検索することができます。
BETWEENを使うことで、カラムをどういう範囲で検索するのかがわかりやすくなります。

たまに、2つの条件をANDでつなげて検索するよりも、BETWEENを使ったほうが速いとか遅いとか言われます。データベースによってアーキテクチャが異なるためSQLの解釈が異なる場合があり実行速度に差が出る場合もありますが、ほとんどのデータベースの場合には速度に差はありません。

// 社員テーブルからIDが100番台のレコードを取得
SELECT *
FROM employee
WHERE id BETWEEN 100 AND 199;

BETWEENでは、数値型のカラムだけではなく、日付型のカラムにも利用することができます。

// 社員テーブルから誕生日が2000/1/1から2000/12/31のレコードを取得
SELECT *
FROM employee
WHERE birthday BETWEEN '2000-01-01' AND '2000-12-31';

BETWEENを使えない場合

BETWEENを使って範囲指定することができますが、条件によってはBETWEENを使うことで正しい結果が得られない場合があります。

// 社員テーブルから身長 [height] が160cm台のレコードを取得
SELECT *
FROM employee
WHERE height BETWEEN 160 AND 169;
// height >= 160 AND height <= 169 と同等

// OK 160.0cm
// OK 169.0cm
// NG 169.5cm
// NG 170.0cm

このように、BETWEEN 160 AND 169 と指定すると、160.0cmから169.0cmまでのレコードはヒットしますが、169.5cmはヒットしません。
小数点以下は切り捨てられてしまうため、169 は169.0として指定されたこととなります。

// 社員テーブルから身長 [height] が160cm台のレコードを取得
SELECT *
FROM employee
WHERE height BETWEEN 160 AND 170;
// height >= 160 AND height <= 170 と同等

// OK 160.0cm
// OK 169.0cm
// OK 169.5cm
// OK 170.0cm

しかし、BETWEEN 160 AND 170 と指定すると、169.0cmや169.5cmのレコードはヒットしますし、170.0cmもヒットしてしまいます。
このような場合には、ANDを使って2つの条件を結びつけるようにします。

日付型のカラムの場合も同様です。年月日しか入っていないカラム(生年月日など)はBETWEENを使ってもOKです。
年月日だけでなく時分秒まで入っているカラム(登録日時など)はBETWEENを使うと、時刻が切り捨てられてしまうのでBETWEENはNGです。

// 社員テーブルから身長 [height] が160cm台のレコードを取得
SELECT *
FROM employee
WHERE height >= 160 AND height < 170

// OK 160.0cm
// OK 169.0cm
// OK 169.5cm
// NG 170.0cm

まとめ

WHERE句を使って、テーブルの中からほしいレコードだけを選択することができます。
等しいもの、〇〇以上や〇〇未満、〇〇以外といった条件を指定することができます。
(=、>、>=、<、<=、NOT)

1つの条件だけでなく、複数の条件を指定するときには、ANDやORで結び付けます。
前方一致や部分一致での検索は、ワイルドカードを使ってLIKEで行います。
範囲指定はBETWEENを使って検索することができます。2つの条件をANDでつなげて指定するのとほぼ同じですが、利用できないときもあるので注意してくださいね。

▶ 一覧に戻る

スポンサーリンク

-SQL, プログラミング

PAGE TOP

© 2021 ちょこぱいぶろぐ Powered by AFFINGER5