# CHAPTER 13: WHERE句

`WHERE`句は、`SELECT`、`UPDATE`、`DELETE`などの コマンドに指定します。コマンドで特定のレコードのみ処理したい場合に 、その特定する条件を指定します。

`WHERE`句を指定しない場合、テーブル内のすべてのレコードが処理され ます。

`WHERE`句は、ブール演算子で構成されます。ブール演算子は、真または偽 で評価する式です。複雑な`WHERE`句になると、`AND`または`OR` により結合したブール演算式で構成されます。優先させたいブール式がある場合には、 括弧で囲んで優先順を制御します。

`WHERE`句は、演算式で比較することによって、フィールド値に基づいた レコードを限定することができます。以下に比較演算子を示します。

Table 13-1: WHERE句の比較演算子

演算子 | 概要
`=` | 一致
`!=` or `<>` or `~=` | 不一致
`!` | 否定
`>` | より大きい
`>=` | 以上
`<` | より小さい
`<=` | 以下
`IN` | フィールド値の複数指定
`RANGE ...` | 値の上限値と下限値を指定
`BETWEEN ...` | RANGEと同一
`LIKE` | パターンマッチ（大文字、小文字の区別有り）
`MATCH` | パターンマッチ（大文字、小文字の区別無し）
`SMATCH` | パターンマッチ（大文字、小文字の区別有り）

`~`は、`!`と同様に使用できます。

Syntax

  `WHERE` | `|b_expr |(b_expr) |b_expr OR b_expr |b_expr AND b_expr |NOT b_expr` | `| | | | |`

  説明

  `b_expr` | ブール式です。詳細はブール式の評価を参照してください。

注意

1. ブール式`b_expr`は、

   `|expr [ |` | `|IS |[IS] NOT`
   | `|] condition |` | `| |`
   `|NULL expr |EXISTS subquery`
   |  | `| |`

   `expr` 式。`expr`の定義は Expressionsを参照してください。

   `condition`は以下のいずれか１つです。

   |  |  | `| | | | | | |` |
   `| = |!= |<> | > |>= | < |<=` | `| | | | | | |` | `|exp |Subquery` | `| |`
   |  | `| | | | | | |`
   |  |  | `| | |` | `IN (expr {, expr}) IN subquery LIKE like_pattern [ESCAPE atom]` |  | `| | |`
   |  |  | `| | | |` |
   `|MATCH |!MATCH |SMATCH |!SMATCH` | `| pattern | | |`
   |  | `| | | |`
   |  |  | `| |` |
   [ | `| = |!=` | `|] NULL |`
   |  | `| | |`
   |  |  | `| |` |
   `BETWEEN` | `|expr |subquery` | `| [ |` | `|EXCLUSIVE |INCLUSIVE` | `|] AND |`
   `|expr |subquery` | `|] |` | `|EXCLUSIVE |INCLUSIVE` | `|] |`
   | `| |`
   |  |  | `| |` |
   `RANGE` | `|expr |subquery` | `| [ |` | `|EXCLUSIVE |INCLUSIVE` | `|] TO |`
   `|expr |subquery` | `|] |` | `|EXCLUSIVE |INCLUSIVE` | `|] |`
   | `| |`

   `subquery` は以下に示す形式のクエリー言語コマンドです。

   |  |  | `[` | `|ANY |ALL` | `|] (select_command) |`

   `like_pattern`文字列を表します。 `like_pattern`には、以下に示す特別な文字を組込むことが できます。

Table 13-2: LIKEパターンマッチング文字

文字 | 概要
_ (underline) | 指定位置には、任意の単一文字が許されます。
% | 指定位置には、任意の文字列が許されます。

`atom`は、(_)や(%)を単一のデータとして、Empressに解釈 させるために使用します。

subqueryのselect_commandは、1つ以上のフィールドに対する集計関数であり、唯一の項目を検索しなければなりません。 この時、`GROUP BY`句の指定、ヘッダーの`PRINT`句を使用することは できません。また必ず括弧で囲む必要があります。 サブクエリーについては、SQL:ユーザーズガイドを参照してください。

`BETWEEN AND`は、`RENGE TO`と同様に使用できます。尚、値を指定 する場合には、必ず昇順で指定しなくてはなりません。 `MATCH`は、大文字、小文字の区別はしませんが、`SMATCH`は区別 します。`MATCH`の前に`(!)`を付加すると、マッチしない 全てのレコードが選択されます。`LIKE`もまた、大文字、小文字の区別をします。

- 通常`WHERE`句における、シンプルなブール式は以下の形式です。

         expr = VALUE

  このブール式は、真か偽、あるいは`NULL`のいずれかの結果を導きます。 式が何らかの原因で評価できなかった場合には、`NULL`となります。

  このように、ブール演算式は3種類の結果のうち、いずれか1つを導くので、複雑な ブール演算式を評価する上では、三値論理が必要となります。この論理から、 `AND`結合、`OR`結合したブール式の規則が決定されます。 以下に、そのテーブルを示します。

  Table 13-3: AND結合

  |  | T | N | F
  T |  | T | N | F
  N |  | N | N | F
  F |  | F | F | F

  Table 13-4: OR結合

  |  | T | N | F
  T |  | T | T | T
  N |  | T | N | N
  F |  | T | N | F

  2つのブール演算式を`AND`結合した場合、ブール演算式全体が真になるには、 それぞれのブール演算式は、真でなくてはなりません。

  2つのブール演算式を`OR`結合した場合、ブール演算式全体が真になるのは、 少なくとも、どちらか一方の演算式が真でなくてはなりません。

- `NOT`と`"!"`は異なることに注意してください。`"!"`は 演算子に対して使用しますが、`NOT`は式に対して使用します。`NOT`を 演算子の前に使いたい場合は、式に変更して使用します。

  例えば、以下のような使い方をしたい場合、

         ... WHERE attr NOT = ANY SELECT ...

  以下のように指定します。

         ... WHERE NOT (attr = ANY SELECT ...)

  または、以下のように指定します。

         ... WHERE attr != ALL SELECT ...

- パターンマッチは、いくつか指定した文字パターン、フィールド値を比較する処理 を行います。パターンが一致した場合、その条件を満たすことになります。

  パターンマッチでは、比較文字列に特殊文字を使用することが可能です。次に使用 できる特殊文字を示します。

  Table 13-5: パターンマッチの特殊文字

  文字 | 概要
  `?` | 指定位置には、任意の単一文字が許可されます。
  `*` | 指定位置には、任意の文字列が許可されます。
  `[...]` | 指定位置には、指定文字セットのいずれかを許可します。 例、`[abc]>/TT>はa、b、cが許可されます。`
  `{...}` | 指定位置には、0以上の文字列を許可します。 例、 `{[a-z]}`は、小文字に英字であれば全て許可します。
  `[.-.]` | 指定位置には、指定範囲のいずれかの文字が許可されます。 例、`[a-cf-i]` は、a、b、c、f、h、iが許可されます。
  `[^...]` | 指定位置には、指定文字セット以外のものを許可します。 例、 `[^abc]`は、a、b、c以外の文字を許可します。
  `...|...` | "|"を境にして、どちらか一方の値で許可されます。 例、`ab|cd` は、abまたはcdが許可されます。
  `...&...` | "&"を境にして、両方の値で許可されます。 例、`[a-z]&[^x]` は"x"以外の任意の文字に許可されます。
  `\` | "?"、"*"、"|"、"&"、"{"、"}"、"["、"]"、"\"などの特殊文字の前に、バックスラッシュを配置した場合、その文字は 特殊文字でなく、その文字自身として許可されます。

  変数を拡張するために使用する文字の場合には、（MSQLVARCHARS変数で定義され、初期値はドル記号です）パターン マッチの用途はまったく無く、文字列におけるその変数拡張機能がそのまま維持されます。従って、この文字を文字列上、 またはパターン上の任意の位置に表現するには、2つのドル記号($$)を指定することにより、変数拡張機能を回避しなけれ ばなりません。

  パターンマッチ例

  例 | 概要
  `*ho*` | このパターンを指定した場合、"ho"の前後に対応する文字の有無、および文字数には関係なく、 "ho"を構成している任意のフィールド値と照合することが可能です。例としてこのパターンは "ho"、"who"、"whom"、"Aho"、"hoho"、"Alphonse"などのフィールド値と一致します。 パターンの前の指定が、SMATCH（大文字、小文字を区別する）である場合には、英小文字の "ho"を使用したパターンが照合されます。パターンの前の指定が、MATCHである場合には、"ho"、 "HO"、"hO"、"Ho"というように、大文字、小文字の区別なしにパターンが照合されます。尚、MATCH、 SMATCHの前に"!"を指定した場合には、一致しないデータが検索されます。
  `12|13` | この場合、12または13とフィールド値が一致しなくてはなりません。
  `R*&*r` | この場合、"Roger"などのRで始まり、rで終了する任意のフィールド値と一致しなくてなりません。 （R*rと指定することもできます。）
  `*Jun*&*1990*` | この場合、Junと1990を含んだフィールド値に限り一致します。例えば"12 June 1990"、"Jun. 12 1990"、 "1990 12 June"、"1990 June 12"、"on the 12th day of June in 1990"、その他いろいろな表記に 一致します。（従ってDATEデータタイプではなく、CHARデータタイプに自由に日付を入力する場合に 有効になります。）
  `f?r` | この場合、fで開始しrで終了する3文字からなる任意の文字列と一致します。例として"fur"、"for"、 "fir"、"far"などがあります。
  `f[uo]r` | この場合、fで開始しrで終了する、中央の文字がuまたはoとなる3文字からなる文字列です。例として "fur"、"for"などです。
  `f[^i]r` | もの場合、中央の文字がi以外の文字であれば、許可されます。例として、"fur"、"for"、"far"などです。
  `E_p` | この場合、Eで始まり、pで終了する3文字からなる、全ての文字列と一致します。

例

1. 以下の`WHERE`句は、`personnel`テーブルから`name` フィールドに"Jones"というデータを持つレコードを検索します。`personnel` テーブル中には、各`name`フィールドごとに、1件のレコードが格納されている ので、単一レコードが検索されます。

          SELECT * FROM personnel
             WHERE name = 'Jones';

   以下を表示します。

          number     name     phone        credit_limit

           3         Jones    667-2951     $500.00

2. 以下の`WHERE`句は、`credit_limit`が$200.00以上のレコードを 検索します。クエリーを指定する場合には、ドル記号は必ずしも指定する必要はありま せん。尚、ドル記号を指定する場合には、そのドル記号の前にもう1つのドル記号を、 指定する必要があります。これはドル記号が間違って、Empress変数であると解釈 されないようにするためです。

          SELECT * FROM personnel
             WHERE credit_limit >= 200.00;

   以下を表示します。

          number     name          phone        credit_limit

          10         Kilroy        426-9681     $500.00
          5          Mosca         544-2243     $750.00
          17         Wladislaw     723-6073     $200.00
          3          Jones         667-2951     $500.00
          8          Peterson      978-6060     $250.00

3. 以下の`WHERE`句は、`name`フィールドに"Kilroy"以外のデータが あり、なおかつ、`credit_limit`フィールドのデータ値が$500.00のレコードを 検索します。`AND`は、その2つの条件を連結するために使用するので、 その条件は、いずれも要求するレコードに対して真でなければなりません。 `"<>"`は`"!="`に置き換えることができます。

          SELECT * FROM personnel
             WHERE name <> 'Kilroy'
             AND credit_limit = '$$500';

   以下を表示します。

          number     name      phone        credit_limit

           3         Jones     667-2951     $500.00

   `credit_limit`の条件には、ドル記号を2つ指定していることに注意して ください。

4. 以下の`WHERE`句は、`loans`テーブルのレコードから、 `date`フィールドのデータが"16 February 1990"であるもの、 または`name`フィールドのデータが"Wladislaw"であるものを選択します。 `OR`は、その2つの条件を連結するために、使用するので、少なくとどちらか 一方の条件が真でなければなりません。

          SELECT * FROM loans
             WHERE date = '16 February 1990'
             OR name = 'Wladislaw';

   以下を表示します。

          name            date                 amount

          Kilroy          16 February 1990     $250.00
          Wladislaw       12 May 1990           $25.00
          Wladislaw       27 February 1990      $55.00
          Wladislaw       25 June 1990          $75.00

5. フィールドの中に、異なる値が含まれているレコードを検索する必要がある場合 には、`OR`を使用して`WHERE`句を複雑に構成することで対処できます。 例えば`loans`テーブルから"Jones"、"Kilroy"、"Mosca"の全てのレコード を検索するには、以下のように指定します。

          SELECT * FROM loans
             WHERE name = 'Jones' OR
             name = 'Kilroy' OR name = 'Mosca';

   この方法とは別に、定数リストを使用して同一の処理を実行することができます。 以下のようなコマンドを実行します。

          SELECT * FROM loans
             WHERE name IN
             ('Jones', 'Kilroy', 'Mosca');

   これにより、複雑な構成で記述する必要がなくなります。

   これと同様に、指定したもの以外の全てのレコードを選択することが可能です。 例えば`loans`テーブルの中から"Jones"、"Kilroy"、"Mosca"以外の全ての レコードを検索するには、次のように指定します。

          SELECT * FROM loans
             WHERE name NOT IN
             ('Jones', 'Kilroy', 'Mosca');

6. 以下の`WHERE`句は、`phone`フィールドにデータが入力されて いないレコードを、すべて検索します。 キーワード`NULL`は、入力されていないデータを意味します。

          SELECT FROM personnel
             WHERE phone = NULL;

   以下のように出力します。

          number     name     phone          credit_limit

   上記のように、`phone`フィールドには`NULL`値のレコードが検索 できないので、フィールド名だけが出力されます。 `NULL`値または、`NULL`値以外の値の検索には、 `"="`および`"!="`の代わりに、`"is"`および`"is not"` キーワードを使用することができます。

          SELECT FROM personnel
             WHERE phone IS NULL;

          SELECT FROM personnel
             WHERE phone IS NOT NULL;

   上記は、`phone`フィールドが`NULL`でないレコードを検索します。

7. 以下の`WHERE`句は、`name`フィールドが"Jones"で、 `date`フィールドが"1 May 1990"より前のレコード、あるいは `name`フィールドが"Wlasdislaw"で、`date`フィールドが "30 April 1990"より後のレコードを検索します。 この場合、括弧を指定してグループ別に分類します。`name`フィールドと `date`フィールドが1つのグループとして条件を指定します。

   `OR`は、括弧内の2つの条件を連結するために使用するので、 少なくともどちらか一方の条件が真でなくてはなりません。以下に示す例では、 それぞれの条件が同時に真になることはありません。

          SELECT FROM loans
             WHERE (name = 'Jones' AND date < '1 May 1990')
             OR (name = 'Wladislaw' AND date > '30 April 1990');

   以下を表示します。

          name               date                 amount

          Jones               7 February 1990     $33.95
          Jones               3 April 1990        $25.00
          Wladislaw          12 May 1990          $25.00
          Wladislaw          25 June 1990         $75.00

   括弧は、必要に応じて論理強調の目的で、`WHERE`句に指定することができ ます。

8. 以下の`WHERE`句は、`amount`フィールドが `credit_limit`フィールドの半分を超えているレコードを検索する 　　コマンドです。

          SELECT name, date, amount
             FROM loans, personnel
             WHERE amount > 0.5 * credit_limit
             AND loans.name = personnel.name;

   以下を表示します。

          name               date                  amount

          Jones              12 August 1990        $300.00
          Scarlatti           9 September 1990     $150.00
          Scarlatti          14 October 1990       $125.00

9. `loans`テーブルの`name`フィールドに名前がある、 `personnel`テーブルのデータを表示します。

          SELECT name, phone, credit_limit
             FROM personnel WHERE exists
             (SELECT name FROM loans
              WHERE loans.name = personnel.name);

   以下を表示します。

          name          phone           credit_limit

          Jones         667-2951        $500.00
          Kilroy        426-9681        $500.00
          Mosca         544-2243        $750.00
          Peterson      978-6060        $250.00
          Scarlatti     961-7363        $100.00
          Wladislaw     723-6073        $200.00

   以下の`WHERE`句は、`loans`テーブルの中から平均値未満の値を 持っている`amount`フィールドのレコードを検索します。そのためにクエリー をネストします。

          SELECT FROM loans
             WHERE amount < (SELECT AVG amount FROM loans);

   以下を表示します。

          name            date                amount

          Jones            7 February 1990    $33.95
          Wladislaw       27 February 1990    $55.00
          Jones            3 April 1990       $25.00
          Wladislaw       12 May 1990         $25.00
          Peterson         6 June 1990        $50.00
          Wladislaw       25 June 1990        $75.00

   以下に示す例は、`loans`テーブルの`amount`フィールドの値が200 を超えている人の情報を、`personnel`テーブルから検索します。

          SELECT name, credit_limit FROM personnel
             WHERE name= ANY
             (SELECT name FROM loans WHERE amount > 200);

          name         credit_limit

          Kilroy       $500.00
          Jones        $500.00

10. 以下の`WHERE`句は、"9"で始まるデータを持つ`phone` フィールドの文字パターンレコードだけ検索します。 パターンマッチを利用した、検索条件の指定例を以下に示します。

           SELECT * FROM personnel
              WHERE phone MATCH '9*';

    以下を表示します。

           number    name        phone       credit_limit

           8        Peterson     978-6060    $250.004
                    Scarlatti    961-7363    $100.00

    以下のコマンドを指定しても、同一の処理結果となります。

           SELECT * FROM personnel
              WHERE phone LIKE '9%';

    以下の`WHERE`句は、任意の文字が先頭にあり（先頭になくても良い）、 その後1つのスペースが続き、"May"の後に、1つのスペースが続き、最後に任意の文字 がある（最後になくても良い）パターンと一致する、`date`フィールド中の パターンレコードのみを検索します。この指定により、任意の年の5月に発生した `loans`テーブルのレコードを検索できます。

           SELECT * FROM loans
              WHERE date MATCH '* May *';

    以下を表示します。

           name            date           amount

           Mosca            4 May 1990    $200.00
           Wladislaw       12 May 1990     $25.00

    `date`フィールド中のデータで、唯一英文字であるのは、月の指定です。 Mayのエントリをすべて検出するための簡潔な指定方法は、以下の方法です。

           SELECT * FROM loans
              WHERE date MATCH '*May*';

    5月以外の月に発生した、レコードを検索するには、以下のコマンドを使用します。

           SELECT * FROM loans WHERE date !MATCH '*May*';

    または

           SELECT * FROM loans WHERE date NOT LIKE '%May%';

    以下を表示します。

           name               date                 amount

           Mosca               2 February 1990     $150.00
           Jones               7 February 1990      $33.95
           Kilroy             16 February 1990     $250.00
           Wladislaw          27 February 1990      $55.00
           Jones               3 April 1990         $25.00
           Peterson            6 June 1990          $50.00
           Wladislaw          25 June 1990          $75.00
           Jones              12 August 1990       $300.00
           Scarlatti           9 September 1990    $150.00
           Scarlatti          14 October 1990      $125.00

    `SMATCH`の効果については、`auto parts`テーブルからの検索に より、具体的に示すことができます。

           SELECT supplier, phone, ATTR 'part name', price
              FROM 'auto parts'
              WHERE ATTR 'part name' SMATCH '*chrome*';

    以下を表示します。

           supplier           phone        part name              price

           AAA Automotive     922-8624     Fender--chrome          $67.95

    ここでは、1レコードのみ表示しています。次のコマンドを使用した場合には、

           SELECT supplier, phone, ATTR 'part name', price
              FROM 'auto parts'
              WHERE ATTR 'part name' MATCH '*chrome*';

    以下の2レコードを表示します。

           supplier             phone        part name              price

           AAA Automotive       922-8624     Fender--chrome        $67.95
           Auto Wholesalers     922-6219     Chrome paint           $1.99

    尚、複合フィールド名で、演算式でないことを明示するために、フィールド名 `part name`の前には、必ず`"ATTR"`キーワードを指定する必要があり ます。

11. 値が与えられた範囲内に位置しているのを見つけるために、`RANGE` キーワードは、次のもののような 複雑な`WHERE`句に優先して使用します。

           WHERE ATTRIBUTE first_constant AND ATTRIBUTE second_constant

    `RANGE`の値を指定する際は、任意のレコードがその条件に合致するように、 必ず昇順に指定しなければなりません。降順に`RANGE`の値を指定しても、 エラーにはなりませんが、レコードは検索されません。 `RANGE`指定の、上限値および下限値は、省略時には範囲内に含まれます。 しかし、`WHERE`句の中で`EXCLUSIVE`を指定すれば、上限値および 下限値は、検索範囲から除外されます。

    `BETWEEN ... AND`は、`RANGE ... TO`の代わりに使用できます。

    次の例は、`loans`テーブルの`amount`フィールドが、 100以上200以下のレコードを検索します。

           SELECT name, date, amount FROM loans
              WHERE amount RANGE 100 to 200;

    以下を表示します。

           name               date                 amount

           Mosca               2 February 1990     $150.00
           Mosca               4 May 1990          $200.00
           Scarlatti           9 September 1990    $150.00
           Scarlatti          14 October 1990      $125.00

    この結果に対して、以下のコマンドを実行した場合。

           SELECT name, date, amount FROM loans
              WHERE amount RANGE 100 EXCLUSIVE TO 200 EXCLUSIVE;

    以下を表示します。

           name               date                amount

           Mosca              2 February 1990      $150.00
           Scarlatti          9 September 1990     $150.00
           Scarlatti          9 September 1990     $125.00

    以下に示す`WHERE`句は、`loans`テーブルの`amount` フィールドの値が、200より大きく、300以下のレコードを検索します。

           SELECT name, date, amount FROM loans
              WHERE amount RANGE 200 EXCLUSIVE TO 300;

    以下を表示します。

           name            date                 amount

           Kilroy          16 February 1990     $250.00
           Jones           12 August 1990       $300.00

12. 値の範囲を指定するには、`BETWEEN ... AND`を使用します。 `BETWEEN ... AND`は`RENGE ... TO`の同義語として使用できます。 また`BETWEEN ... AND`は、複雑なブール演算式を指定することもできますが、 その場合の評価の際には多くの時間を費やします。

           SELECT * FROM table WHERE
              attr BETWEEN value AND value;

    上記指定は、次の指定と同一です。

           SELECT * FROM table WHERE
              attr RANGE value TO value;

    よって、前に示した`loans`テーブルの`amount`フィールドのデータ が、100より大きく、200より小さいレコードの選択は、次のように指定することも可能 です。

           SELECT name, date, amount FROM loans
              WHERE amount BETWEEN 100 EXCLUSIVE AND 200 EXCLUSIVE;

    以下に示すような、同一の結果を表示します。

           name                date                 amount

           Mosca               2 February 1990      $150.00
           Scarlatti           9 September 1990     $150.00
           Scarlatti           9 September 1990     $125.00

    尚、`RENGE ... TO`を指定した場合と同様に、任意のレコードがその条件に 合致するように、必ず昇順に値を指定しなければなりません。