SQL SELECT基礎(4-2) 行を減らす (WHERE 制限)

この記事は「SQL SELECT基礎」の第4回目です。
[SQL SELECT基礎 目次](http://qiita.com/Hiraku/items/67cf329f1ddb897b1436)
←前の記事は[SQL SELECT基礎(4-1) 列を減らす (project 射影)](http://qiita.com/Hiraku/items/abc592d2b19b671669b1)
→次の記事は[SQL SELECT基礎(4-3) 縦方向にくっ付ける (UNION 和)]()

## 表の加工(2) 行を減らす (WHERE 制限)

SELECT文は、既にある表を加工してその場で別の表を作っていく構文です。
おそらく最も使うと思われるのが、WHERE句です。projectionでは列を絞り込むことができましたが、WHERE句では条件に応じて行を絞り込むことができます。
restriction(制限)操作と言ったりもします。

こう、横一列を削るイメージです。
<img width="400" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/1126/53be2bcf-cbef-b236-9479-e4763c7d94cd.png">

構文は単純で、今まで書いていたSELECT文のFROM句の次に`WHERE 真偽値`と書きます。

```sql
SELECT * FROM sample WHERE TRUE
```

WHEREがあると、その条件がTRUEになる行だけに絞り込まれて結果が返ってきます。



### 今回のサンプル表

<img width="206" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/1126/089763b4-4d93-d76a-b962-30060e34ca59.png">


使いまわしですが、こんな感じで。

```sql
(
SELECT 1 AS id, "taro" AS name, "1990-01-01" AS birthday
UNION ALL
SELECT 2, "hanako", "1995-04-12"
UNION ALL
SELECT 3, "jiro", "2004-03-02"
) AS sample
```

### 真偽値について

ところで、WHERE句はprojectionよりも理解が難しい概念です。SQL中の真偽値を理解する必要があるからです。

真偽値というと、「true」か「false」のどちらかを表す言葉です。プログラミング言語によっては専用の変数型を持っていることもあります。
MySQLの場合、数字の0がfalse相当、それ以外の数字はtrue相当として認識されます。
`TRUE` と `FALSE` もキーワードとして認識しますが、それぞれ1と0と同じ意味として扱われます。

```sql
SELECT TRUE; -- -> 1
SELECT FALSE; -- -> 0
```

> リレーショナルデータベースにおける真偽値には、正確にはもう一つ、`NULL(unknown)`という特殊な状態を加味する必要があるのですが、後ほど記事を書くので一旦考えないことにします。

### WHERE句に書ける条件いろいろ

WHERE句では各行の値を使って条件を書くことができます。

```sql
SELECT *
  FROM sample 
 WHERE id = 1
```

たとえばこれ。何となく意味が想像つくかもしれませんが、「idが1と一致する」ときだけWHERE句の中身がtrueになります。この場合はid=1の行だけに絞られて結果が返ってきます。

<img width="183" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/1126/793176c8-8048-333f-343c-04b72b4b7db8.png">

なお、「id」をクォーテーションでくくってないことに注意して下さい。突然、生で文字列が出てきた場合、MySQLは特別なものとして解釈しようとします。この場合、各行の値をあてはめながら処理をしていくイメージになります。

WHERE句の目的は結果を減らすことですから、大抵の条件はこんな書き方になります。

|列の名前 |比較方法 |具体的なスカラ値|
|:-:|:-:|:-:|
|id |= |1 | 

もっとも、こんな書き方に限らず「結果が真偽値になるならなんでも書ける」ので、わざわざ四則演算を挟むこともできますし、

|列の名前 |比較方法 |具体的なスカラ値|
|:-:|:-:|:-:|
|id |= |1 + 2  |

右辺と左辺をひっくり返しても大丈夫ですし、

|具体的なスカラ値 |比較方法 |列の名前|
|:-:|:-:|:-:|
|1 |= |id | 

列と列を比較に使うこともできます。(このsampleの場合は使いみちがないですが…）

|列の名前 |比較方法 |列の名前|
|:-:|:-:|:-:|
|name |= |birthday | 

### 比較方法いろいろ

使える比較演算は、他のプログラミング言語でもよく見るものが多いでしょう。

| 比較演算子 | 意味 |
|:-:|:-:|
| `=` | 左辺と右辺が同じ値のときtrue  |
| `>` | 左辺の方が大きいときにtrue、同値はfalse |
| `<` | 左辺の方が小さいときにtrue、同値はfalse |
| `>=` | 同値でもtrueになる `>` |
| `<=` | 同値でもtrueになる `<` |
| `!=`, `<>` | 左辺と右辺が違う値のときにtrue |

数字の場合、大小はそのまま数字の大小ですが、
文字列の場合、アルファベット順、辞書順で大小が判定されます。


### ANDとOR

複数の条件を含む場合は、ANDやORでつなぐことが出来ます。

ANDは両方を満たす場合にtrueで、

```sql
SELECT *
  FROM sample
 WHERE id >= 2
   AND birthday <= '2000-01-01'
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1126/4997d418-7f2d-8c3b-3a8f-7ea133790b3e.png)

ORはどちらか一方でも満たしていればtrueです。

```sql
SELECT *
  FROM sample
 WHERE id >= 2
    OR birthday <= '2000-01-01'
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1126/84348d5a-471f-791e-a3f8-f2b461557611.png)


ANDとORが両方出てくる場合、先にANDでつながっているところが処理され、なるべく後でORが処理されます。
先にOR条件を使いたい場合は、カッコ `()` でくくります。


```sql
SELECT *
  FROM sample
 WHERE (   id = 1
        OR id = 2)
   AND birthday <= '2000-01-01'
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1126/4efde406-2a95-e28d-9ca8-a69a8f43b9c3.png)


> なお、MySQLに限らずですが、データベースの検索条件で「OR」を使うと動作が遅くなることが多いです。
> 後述するIN句を活用したり、なるべくOR以外の書き方をするのがよいです。

### BETWEEN A AND B

特殊な比較演算として、BETWEENという書き方があります。

```sql
id BETWEEN 1 AND 3
```

これは

```sql
id >= 1 AND id <= 3
```

とまったく同じ意味です。1から3の間ってことですね。両端を含むことに注意が必要です。
ちょっとスッキリ書けてオシャレです。

### IN

ORの代替として、INという書き方もあります。INの後ろに列挙されたもののいずれかに合致すれば、trueです。

```sql
id IN (1,2,3)
```

### NOT IN

否定形でNOT INというのもあります。INの後ろに列挙されたものに含まれていなければ、trueです。

```sql
id NOT IN (2,4,6)
```

イメージが掴めてきたでしょうか？
これ以外にも書き方次第で色々できるのですが、追々説明していくことにします。