備忘録的プログラミングリファレンス

WHERE 句

 WHERE 句は行データをフィルタリング(抽出)する条件を設定するためのものです。SELECTUPDATEDELETE 文で使用し、対象となる行を絞り込むことができます。

WHERE 句
> SELECT * FROM sales_slip
 	WHERE goods_id = 1;

 WHERE 句を使用しない場合はすべての行が対象になります。

 WHERE 句における評価は、カラム = 式というようなカラムと式による比較によって行います。

 WHERE 句による条件には、等価、不等価、範囲、文字列、NOT、NULLといった条件を設定することができます。

 それらの条件は AND、OR 演算子によって組み合わせることができます。

設定条件概要
等価=
不等価!= または <>
範囲><>=<=といった比較演算子。BETWEEN、IN、サブクエリ
文字列比較文字列の検索。正規表現やワイルドカードの使用
NOT否定
NULL値がない

このページで使う例

 以降の例では、以下のようなデータを使用しています。

SELECT * FROM goods;
+----+----------------+------------+
| id | name           | unit_price |
+----+----------------+------------+
|  1 | candy          |          3 |
|  2 | snack          |          5 |
|  3 | chocolate      |          8 |
|  4 | ice            |          8 |
|  5 | lollipop candy |         15 |
+----+----------------+------------+
...

select * from sales_slip;
+----+---------------------+----------+------------+--------+
| id | date_time           | goods_id | unit_price | amount |
+----+---------------------+----------+------------+--------+
|  1 | 2023-09-26 22:29:57 |        1 |          3 |    100 |
|  2 | 2023-09-26 22:29:58 |        2 |          8 |     50 |
|  3 | 2023-09-28 22:42:10 |        2 |          5 |     30 |
|  4 | 2023-09-28 22:42:10 |        1 |          5 |     80 |
|  5 | 2023-09-28 22:42:53 |        3 |         10 |     10 |
+----+---------------------+----------+------------+--------+
...

 このデータは、テーブルページの外部キー制約( FOREIGN KEY )の作成例です。

WHERE について

 WHERE 句は、SELECTUPDATEDELETE 文に検索条件を加えます。

 HWERE 句が示す検索条件は、比較演算子( =、!=、<>、>、<、>=、<= )や BETWEEN、IN 句、文字列の比較などによって作成します。
 これらの条件を true または false に評価し、true である行のみを抽出します。

WHERE 句
> SELECT * FROM sales_slip
 	WHERE goods_id = 1;
+----+---------------------+----------+------------+--------+---------+
| id | date_time           | goods_id | unit_price | amount | user_id |
+----+---------------------+----------+------------+--------+---------+
|  1 | 2023-10-29 07:17:00 |        1 |          3 |    100 |       1 |
|  4 | 2023-09-28 22:42:10 |        1 |          5 |     80 |       2 |
+----+---------------------+----------+------------+--------+---------+

 例えば、上記のような場合は WHERE 以降の goods_id = 1 が true として評価される行のみを抽出しています。

条件

 WHERE 句に設定する条件は主に以下のように分けることができます。

設定条件概要
等価=
不等価!= または <>
範囲><>=<=といった比較演算子。BETWEEN、IN、サブクエリ
文字列比較文字列の検索。正規表現やワイルドカードの使用
NOT否定
NULL値がない

 WHERE 句における評価は カラム = 式などのようにカラムと式を比較することで評価します。

等価条件

 等価条件とは カラム = 式 で表され、カラムデータと式による値が等しいという条件になります。

> SELECT * FROM sales_slip
 	WHERE goods_id = 1;
+----+---------------------+----------+------------+--------+
| id | date_time           | goods_id | unit_price | amount |
+----+---------------------+----------+------------+--------+
|  1 | 2023-09-26 22:29:57 |        1 |          3 |    100 |
|  4 | 2023-09-28 22:42:10 |        1 |          5 |     80 |
+----+---------------------+----------+------------+--------+

不等価条件

 不等価条件とは カラム != 式 または カラム <> 式 で表され、カラムデータと式による値が等しくないという条件になります。

> SELECT * FROM sales_slip
 	WHERE goods_id != 1;
+----+---------------------+----------+------------+--------+
| id | date_time           | goods_id | unit_price | amount |
+----+---------------------+----------+------------+--------+
|  2 | 2023-09-26 22:29:58 |        2 |          8 |     50 |
|  3 | 2023-09-28 22:42:10 |        2 |          5 |     30 |
|  5 | 2023-09-28 22:42:53 |        3 |         10 |     10 |
+----+---------------------+----------+------------+--------+

 !=<>とも表すことができます。

範囲条件

 データの以上 >=、以下 <=や最小値から最大値 <= AND >= によって範囲を指定することもできます。
 より大きい >、より小さい < といった指定もできます。

 最小値から最大値といった範囲に限っては BETWEEN 演算子を使用することもできます。

 さらに、複数の条件が該当するといったことを指定する IN を使用する方法もあります。

以上

 以上を表すのは カラム名 >= 式です。

> SELECT * FROM sales_slip
 	WHERE amount >= 50;
+----+---------------------+----------+------------+--------+
| id | date_time           | goods_id | unit_price | amount |
+----+---------------------+----------+------------+--------+
|  1 | 2023-09-26 22:29:57 |        1 |          3 |    100 |
|  2 | 2023-09-26 22:29:58 |        2 |          8 |     50 |
|  4 | 2023-09-28 22:42:10 |        1 |          5 |     80 |
+----+---------------------+----------+------------+--------+

 =>はエラーが出ることがあります。

 >ではより大きいを表します。

> SELECT * FROM sales_slip
 	WHERE amount > 50;
+----+---------------------+----------+------------+--------+
| id | date_time           | goods_id | unit_price | amount |
+----+---------------------+----------+------------+--------+
|  1 | 2023-09-26 22:29:57 |        1 |          3 |    100 |
|  4 | 2023-09-28 22:42:10 |        1 |          5 |     80 |
+----+---------------------+----------+------------+--------+

以下

 以下を表すのは カラム名 <= 式です。

> SELECT * FROM sales_slip
 	WHERE amount <= 50;
+----+---------------------+----------+------------+--------+
| id | date_time           | goods_id | unit_price | amount |
+----+---------------------+----------+------------+--------+
|  2 | 2023-09-26 22:29:58 |        2 |          8 |     50 |
|  3 | 2023-09-28 22:42:10 |        2 |          5 |     30 |
|  5 | 2023-09-28 22:42:53 |        3 |         10 |     10 |
+----+---------------------+----------+------------+--------+

 =<はエラーが出ることがあります。

 <ではより小さいを表します。

> SELECT * FROM sales_slip
 	WHERE amount < 50;
+----+---------------------+----------+------------+--------+
| id | date_time           | goods_id | unit_price | amount |
+----+---------------------+----------+------------+--------+
|  3 | 2023-09-28 22:42:10 |        2 |          5 |     30 |
|  5 | 2023-09-28 22:42:53 |        3 |         10 |     10 |
+----+---------------------+----------+------------+--------+

最小値から最大値

 最小値から最大値の範囲を表すには カラム名 >= 式 AND カラム名 <= 式 があります。

> SELECT * FROM sales_slip
	WHERE amount >= 30 AND amount <= 80;
+----+---------------------+----------+------------+--------+
| id | date_time           | goods_id | unit_price | amount |
+----+---------------------+----------+------------+--------+
|  2 | 2023-09-26 22:29:58 |        2 |          8 |     50 |
|  3 | 2023-09-28 22:42:10 |        2 |          5 |     30 |
|  4 | 2023-09-28 22:42:10 |        1 |          5 |     80 |
+----+---------------------+----------+------------+--------+

 より大きい>、より小さい<を使用することもできます。

 もしも式を文字列として指定しても同じような結果が返ります。

> SELECT * FROM sales_slip
	WHERE amount >= '30' AND amount <= '80';
+----+---------------------+----------+------------+--------+
| id | date_time           | goods_id | unit_price | amount |
+----+---------------------+----------+------------+--------+
|  2 | 2023-09-26 22:29:58 |        2 |          8 |     50 |
|  3 | 2023-09-28 22:42:10 |        2 |          5 |     30 |
|  4 | 2023-09-28 22:42:10 |        1 |          5 |     80 |
+----+---------------------+----------+------------+--------+

 これは文字列をデータベースが文字セットの番号に変換するために検索することができます。

BETWEEN 演算子

 最小値から最大値の範囲を表す方法には BETWEEN 演算子もあります。

> SELECT * FROM sales_slip
	WHERE amount BETWEEN 30 AND 80;
+----+---------------------+----------+------------+--------+
| id | date_time           | goods_id | unit_price | amount |
+----+---------------------+----------+------------+--------+
|  2 | 2023-09-26 22:29:58 |        2 |          8 |     50 |
|  3 | 2023-09-28 22:42:10 |        2 |          5 |     30 |
|  4 | 2023-09-28 22:42:10 |        1 |          5 |     80 |
+----+---------------------+----------+------------+--------+

IN 演算子

 範囲ではなく、複数の条件を検索するには IN 演算子を使用します。

> SELECT * FROM sales_slip
	WHERE goods_id IN( 1, 2 );
+----+---------------------+----------+------------+--------+
| id | date_time           | goods_id | unit_price | amount |
+----+---------------------+----------+------------+--------+
|  1 | 2023-09-26 22:29:57 |        1 |          3 |    100 |
|  4 | 2023-09-28 22:42:10 |        1 |          5 |     80 |
|  2 | 2023-09-26 22:29:58 |        2 |          8 |     50 |
|  3 | 2023-09-28 22:42:10 |        2 |          5 |     30 |
+----+---------------------+----------+------------+--------+

 これは WHERE 句で OR を使用した方法と同じで、OR を複数使用するより上記のように IN を使用した方が簡易になります。

SELECT * FROM sales_slip
	WHERE goods_id = 1 OR goods_id = 2;

NOT IN 演算子

 複数の条件を検索する IN 演算子を否定条件にするには NOT を加えます。

> SELECT * FROM sales_slip
	WHERE goods_id NOT IN( 1, 2 );
+----+---------------------+----------+------------+--------+
| id | date_time           | goods_id | unit_price | amount |
+----+---------------------+----------+------------+--------+
|  5 | 2023-09-28 22:42:53 |        3 |         10 |     10 |
+----+---------------------+----------+------------+--------+

NOT 演算子

 NOT 演算子は比較演算子( =、!=、><、>、<、>=、<= )や BETWEEN、IN 句、文字列の比較、NULL による評価を反対にする演算子です。
 例えば評価が true であった場合には false に、false であった場合は true になります。

 例えば以下のようなWHERE goods_id = 1という検索条件があります。

> SELECT * FROM sales_slip
 	WHERE goods_id = 1;

 この検索条件にNOTを加えると以下のようになります。

> SELECT * FROM sales_slip
 	WHERE NOT ( goods_id = 1 );
+----+---------------------+----------+------------+--------+---------+
| id | date_time           | goods_id | unit_price | amount | user_id |
+----+---------------------+----------+------------+--------+---------+
|  2 | 2023-09-26 22:29:58 |        2 |          8 |     50 |       1 |
|  3 | 2023-09-28 22:42:10 |        2 |          5 |     30 |       1 |
|  5 | 2023-09-28 22:42:53 |        3 |         10 |     10 |       3 |
+----+---------------------+----------+------------+--------+---------+

 NOT として評価する式は分かりやすくカッコ(..)で囲んでします。このことでカッコ(..)内の内容が先に処理されます。

サブクエリ

 WHERE 句に使用する条件が固定されたリテラル値ではなく、保存されているデータを条件にしたい場合があります。
 あるテーブルのデータの抽出結果を別のテーブルデータの抽出条件にするといった場合です。例えば、ある日に売れた商品 ID のみや女性のみの会員を条件にするやなどです。

 以下の例は意味がありませんが、sales_slip テーブルの 50 個以上売り上げた商品名データを goods テーブルから抽出します。

> SELECT * FROM goods
	WHERE id IN ( SELECT goods_id FROM sales_slip WHERE amount >= 50 );
+----+-------+------------+
| id | name  | unit_price |
+----+-------+------------+
|  1 | candy |          3 |
|  2 | snack |          5 |
+----+-------+------------+

 結合すれば済むようなことですが、このように常に変動する売上データを条件とするような場合にはサブクエリが有用です。

 サブクエリについて詳しくはサブクエリ ( 副問合せ )ページを参照してください。

文字列の比較

 文字列の検索には正規表現や LIKE 演算子による簡易なパターンマッチが使用できます。

正規表現

 MySQL では REGEXP 演算子で、PostgreSQL では ~ 演算子を使用します。他にも関数がありますが、詳しくはそれぞれの正規表現で調べてみてください。

 以下の例は MySQL の REGEXP 演算子を使用した、頭文字がcで始まる name カラムデータの行を抽出しています。

MySQL の REGEXP 演算子
> SELECT * FROM goods
	WHERE name REGEXP '^[c]';
+----+-----------+------------+
| id | name      | unit_price |
+----+-----------+------------+
|  1 | candy     |          3 |
|  3 | chocolate |          8 |
+----+-----------+------------+

 PostgreSQL で正規表現を使用するには ~ 演算子または regexp_replace 関数、SIMILAR TO 演算子を利用します。

PostgreSQL の ~ 演算子
> SELECT * FROM goods
	WHERE name ~ '^[c]';
+----+-----------+------------+
| id | name      | unit_price |
+----+-----------+------------+
|  1 | candy     |          3 |
|  3 | chocolate |          8 |
+----+-----------+------------+

 REGEXP 演算子は引数に該当する文字列があるか/ないかを数値で返します。True なら 1 を False なら 0 を返します。

 例えば上記のような REGEXP 演算子を SELECT 句の直後に使用すると 1 または 0 を返します。

REGEXP 演算子
> SELECT name, name REGEXP '^[c]'
	FROM goods;
..
| name           | name REGEXP '^[c]' |
+----------------+--------------------+
| candy          |                  1 |
| snack          |                  0 |
| chocolate      |                  1 |
| ice            |                  0 |
| lollipop candy |                  0 |
| test           |                  0 |
| test b         |                  0 |
..

 正規表現の記述方法については基本的な正規表現の使い方も参照してみてください。

簡易なパターン

 正規表現はその記述方法が複雑ですが、LIKE 演算子による簡易なパターンマッチの方法も用意されています。
 正規表現に比べて柔軟性に欠けますが、パターンマッチで十分な場合もあります。

 LIKE 演算子によるパターンマッチには以下のワイルドカード文字を使用します。

  • % .. 0 文字以上を表す
  • _ .. 1 文字を表す

 例えば c で始まる文字列を合わすには以下のように 'c%' とします。

ワイルカード文字 %
> SELECT * FROM goods
	WHERE name LIKE 'c%';
+----+-----------+------------+
| id | name      | unit_price |
+----+-----------+------------+
|  1 | candy     |          3 |
|  3 | chocolate |          8 |
+----+-----------+------------+

 _はある 1 文字があることを表します。例えば電話番号を表す文字列は '___-___-____' のように記述できます。
 以下の例はある年の 9 月の日付をもつ行を抽出します。

ワイルカード文字 _
> SELECT * FROM sales_slip
	WHERE date_time LIKE '____-09-__ __:__:__';
 +----+---------------------+----------+------------+--------+
 | id | date_time           | goods_id | unit_price | amount |
 +----+---------------------+----------+------------+--------+
 |  1 | 2023-09-26 22:29:57 |        1 |          3 |    100 |
 |  2 | 2023-09-26 22:29:58 |        2 |          8 |     50 |
 |  3 | 2023-09-28 22:42:10 |        2 |          5 |     30 |
 |  4 | 2023-09-28 22:42:10 |        1 |          5 |     80 |
 |  5 | 2023-09-28 22:42:53 |        3 |         10 |     10 |
 +----+---------------------+----------+------------+--------+

 LIKE 演算子は引数に該当する文字列があるか/ないかを数値で返します。True なら 1 を False なら 0 を返します。

 例えば上記の LIKE 演算子を SELECT 句の直後に使用すると 1 または 0 を返します。

LIKE 演算子
> SELECT id, date_time LIKE '____-09-__ __:__:__' AS test FROM sales_slip;
..
| id | test |
+----+------+
|  1 |    0 |
|  2 |    1 |
|  3 |    1 |
|  4 |    1 |
|  5 |    1 |
..

NULL

 NULL は何もないことを表す特殊な値です。カラムデータに何も入力してない場合は NULL として表されます。
 カラム = NULLという NULL を式や値として比較することができません。NULL であるかどうかは IS NULL という特殊な演算子を使用する必要があります。

IS NULL 演算子
> SELECT * FROM sales_slip
         WHERE goods_id IS NULL;
Empty set (0.00 sec)

 goods_id が NULL である行はないようです。では NULL でないIS NOT NULLではどうでしょうか。

IS NOT NULL 演算子
> SELECT * FROM sales_slip
	WHERE goods_id IS NOT NULL;
 +----+---------------------+----------+------------+--------+
 | id | date_time           | goods_id | unit_price | amount |
 +----+---------------------+----------+------------+--------+
 |  1 | 2023-09-26 22:29:57 |        1 |          3 |    100 |
 |  4 | 2023-09-28 22:42:10 |        1 |          5 |     80 |
 |  2 | 2023-09-26 22:29:58 |        2 |          8 |     50 |
 |  3 | 2023-09-28 22:42:10 |        2 |          5 |     30 |
 |  5 | 2023-09-28 22:42:53 |        3 |         10 |     10 |
 +----+---------------------+----------+------------+--------+

 すべて表示されました。goods_id が NULL である行はないことが分かります。

AND、OR 演算子

 複数の条件を設定することが AND や OR 句によってできます。

 AND は、この句を挟んだ両側の条件がともに true である場合に限り true と評価します。

 AND 句における評価の組み合わせは以下のようになります。

組み合わせ評価
true AND true true
true AND false false
false AND true false
false AND false false
AND 演算子
> SELECT * FROM sales_slip
	WHERE goods_id = 1 AND amount >= 100;
 +----+---------------------+----------+------------+--------+
 | id | date_time           | goods_id | unit_price | amount |
 +----+---------------------+----------+------------+--------+
 |  1 | 2023-09-26 22:29:57 |        1 |          3 |    100 |
 +----+---------------------+----------+------------+--------+

 例えば上記の場合は goods_id = 1( 商品IDが 1 ) かつ amount >= 100 ( 売上数量が 10 以上 )の場合に限り ture になります。

 OR 句は、この句を挟んだ両側の条件のどちらかが true である場合に true と評価します。

OR 演算子
> SELECT * FROM sales_slip
	WHERE goods_id = 1 OR goods_id = 2;
+----+---------------------+----------+------------+--------+---------+
| id | date_time           | goods_id | unit_price | amount | user_id |
+----+---------------------+----------+------------+--------+---------+
|  1 | 2023-10-29 07:17:00 |        1 |          3 |    100 |       1 |
|  4 | 2023-09-28 22:42:10 |        1 |          5 |     80 |       2 |
|  2 | 2023-09-26 22:29:58 |        2 |          8 |     50 |       1 |
|  3 | 2023-09-28 22:42:10 |        2 |          5 |     30 |       1 |
+----+---------------------+----------+------------+--------+---------+

 例えば上記の場合は goods_id = 1( 商品IDが 1 ) または goods_id = 2( 商品IDが 2 )の場合が ture になります。

 OR 句における評価の組み合わせは以下のようになります。

組み合わせ評価
true AND true true
true AND false true
false AND true true
false AND false false

カッコ ( .. ) による評価順

 これらの AND や OR 句による条件の設定は複数を組み合わせることができます。

 例えば goods_id = 1( 商品IDが 1 ) または goods_id = 2( 商品IDが 2 )で amount >= 50 ( 売上数量が 50 以上 )である場合は以下のようになります。

AND と OR 演算子の組み合わせ
> SELECT * FROM sales_slip
	WHERE ( goods_id = 1 OR goods_id = 2 ) AND amount >=50 ;
+----+---------------------+----------+------------+--------+---------+
| id | date_time           | goods_id | unit_price | amount | user_id |
+----+---------------------+----------+------------+--------+---------+
|  1 | 2023-10-29 07:17:00 |        1 |          3 |    100 |       1 |
|  4 | 2023-09-28 22:42:10 |        1 |          5 |     80 |       2 |
|  2 | 2023-09-26 22:29:58 |        2 |          8 |     50 |       1 |
+----+---------------------+----------+------------+--------+---------+

 上記はカッコ ( .. ) を使用しています。カッコ ( .. ) は、囲まれた内容を優先的に評価します。
 上記の場合は goods_id = 1 または goods_id = 2 である行を抽出し、amount >= 50 である行を true として抽出しています。

 SQL 文においてカッコ ( .. ) 内は常に優先的に処理されます。

 このことは、サブクエリでも同じことがいえます。

> SELECT * FROM goods
	WHERE id IN ( SELECT goods_id FROM sales_slip WHERE amount >= 50 );

 サブクエリは常にカッコ ( .. ) で囲むようにします。このことで先に処理させるようにしています。