WHERE 句
WHERE 句は行データをフィルタリング(抽出)する条件を設定するためのものです。SELECT、UPDATE、DELETE 文で使用し、対象となる行を絞り込むことができます。
> SELECT * FROM sales_slip
WHERE goods_id = 1;
WHERE 句を使用しない場合はすべての行が対象になります。UPDATE や DELETE 文では WHERE 句を使うようにします。
WHERE 句における評価は、カラム = 式
というようなカラムと式による比較によって行います。
WHERE 句による条件には、等価、不等価、範囲、文字列、NOT、NULLといった条件を設定することができます。
| 設定条件 | 概要 |
|---|---|
| 等価 | = |
| 不等価 | !=または <> |
| 範囲 | >、 <、 >=、 <=といった比較演算子。BETWEEN、IN、サブクエリ |
| 文字列比較 | 文字列の検索。正規表現やワイルドカードの使用 |
| NOT | 否定 |
| NULL | 値がない |
これらの条件は AND、OR 演算子によって組み合わせることができます。
> SELECT * FROM sales_slip
WHERE goods_id >= 1 AND goods_id <= 5 ;
ページ内 Index
このページで使う例
以降の例では、以下のようなデータを使用しています。
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 句は、SELECT や UPDATE、DELETE 文に検索条件を加えます。
HWERE 句が示す検索条件は、比較演算子( =、!=、<>、>、<、>=、<= )や BETWEEN、IN 句、文字列の比較などによって作成します。
これらの条件を true または false に評価し、true である行のみを抽出します。
> 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 カラムデータの行を抽出しています。
> SELECT * FROM goods
WHERE name REGEXP '^[c]';
+----+-----------+------------+
| id | name | unit_price |
+----+-----------+------------+
| 1 | candy | 3 |
| 3 | chocolate | 8 |
+----+-----------+------------+
PostgreSQL で正規表現を使用するには ~ 演算子または regexp_replace 関数、SIMILAR TO 演算子を利用します。
> 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 を返します。
> 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 を返します。
> 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 という特殊な演算子を使用する必要があります。
> SELECT * FROM sales_slip
WHERE goods_id IS NULL;
Empty set (0.00 sec)
goods_id が NULL である行はないようです。では 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 |
> 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 と評価します。
> 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 以上 )である場合は以下のようになります。
> 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 );
サブクエリは常にカッコ ( .. )
で囲むようにします。このことで先に処理させるようにしています。
