テクノロジー:SQLの基礎
WHEREはなぜ重要か著者:Melanie Caffrey
リレーショナル・データベースとSQLの基本に関するシリーズ記事のパート4 このシリーズ記事のパート3"SELECTを使用して答えを得る"(Oracle Magazine、2012年1/2月)では、SELECT文(問合せ)の構造と、関心のあるデータがどの表に格納されているかを突き止めることがいかに重要であるかを説明しました。SELECT文の基本的な機能について理解できたので、次にデータをフィルタして、意味のある出力になるように限定することができます。WHERE句によって、SELECT文が取得する(つまりフェッチする)データの範囲を絞り込むことができます。この記事では、WHERE句、および関連する比較演算子と論理演算子について詳しく取り上げます。 この記事やシリーズの今後の記事の例を試すには、Oracle Databaseインスタンスにアクセスする必要があります。必要に応じて、お使いのオペレーティング・システムに対応したOracle Databaseエディションをダウンロードし、インストールしてください。筆者がインストールをお勧めするエディションは、Oracle Database, Express Editionです。 このOracle Databaseソフトウェアをインストールする場合は、データベースの作成と構成が可能なインストール・オプションを選択してください。サンプルのユーザー・アカウントと関連する新しいスキーマを含む新しいデータベースが作成されます(このシリーズのパート1で説明したとおり、一般的にスキーマとは、類似したビジネス機能を扱う表などのオブジェクトのグループのことです)。SQL_101は、この記事の例で使用するユーザー・アカウントです。また、データベースの表やその他のオブジェクトが作成されるスキーマでもあります。インストール・プロセスの実行中にスキーマのパスワードを指定するように求められたら、SYSおよびSYSTEMのパスワードを入力して確認し、そのパスワードを覚えておいてください。最後に、このデータベース・ソフトウェアをゼロからインストールした場合でも、既存のOracle Databaseインスタンスにアクセスする場合でも、SQLスクリプトをダウンロードして解凍し、実行して、SQL_101スキーマ用にサンプルの表を作成します。 この記事のSQL問合せは、SQL*Plusツールを使用してSQL_101スキーマ内の表に対して実行されます。 比較による制限値の設定問合せによって取得するデータをフィルタするには、SQL文にWHERE句を追加します。WHERE句は、条件リストや条件セットとも呼ばれます。一言で言えば、WHERE句は、問合せの結果セットにレコードを含めるために満たす必要のある基準を表したものです。WHERE句には、データベース・ソフトウェアによってtrueまたはfalseと評価されるWHERE句の条件 (単数または複数)を指定する必要があります。ただし、値がないことについては、データベース・ソフトウェアによって自動的に判定できます。WHERE句は条件式で構成されます。条件式の形式は次のとおりです。 <左側の式> <比較演算子> <右側の式> よくある条件式の形式について、次にいくつかの例を挙げます。 WHERE <column_name> = <literal_character_value> WHERE <column_name> IN (3, 7, 9) WHERE <column_name> >= 100 WHERE <column_name> LIKE 'E%'; WHERE <column_name> BETWEEN 100 AND 500;
リテラル文字の値、または文字列とは、'Smith'、'73abc'、'15-MAR-1965'など、任意の英数字の並びを一重引用符で囲んだものです。 比較演算子は、複数の式を比較して、選択対象となる適切なデータを判定します。表1に、よく使用される比較演算子について示します。
表1:SQL WHERE句の比較演算子 等価(非等価)の重要性もっともよく使用される比較演算子は、等価演算子の=です。たとえば、年間給与が$70,000であるすべての従業員の名前と雇用日を検索する場合、リスト1のSQL問合せを実行できます。 コード・リスト1:給与が$70,000である従業員を検索するための問合せ SQL> select first_name, last_name, hire_date, salary 2 from employee 3 where salary = 70000; FIRST_NAME LAST_NAME HIRE_DATE SALARY ----------- ------------- ------------ ----------- Matthew Michaels 16-MAY-07 70000 1 row selected.
SALARY列に格納された値がリテラル値70000と比較され、値が等しいかどうかが判定されます。このWHERE句の条件を満たす各行が取得されます。 問合せの結果から特定のデータを除外したい場合もあります。たとえば、リスト1の問合せを実行して結果を取得したため、Matthew Michaelsという従業員の名前、雇用日、給与についてすでに把握しているとしましょう。他のすべての従業員について同じ情報を取得するには、リスト2の問合せを実行できます。見てのとおり、この問合せでは非等価演算子の!=を使用して、LAST_NAMEの値がMichaelである行を除くすべての行を取得しています。 コード・リスト2:従業員Michaelを除外する問合せ SQL> select first_name, last_name, hire_date, salary 2 from employee 3 where last_name != 'Michaels'; FIRST_NAME LAST_NAME HIRE_DATE SALARY ----------- ------------- ------------ ----------- Frances Newton 14-SEP-05 75000 Emily Eckhardt 07-JUL-04 100000 Donald Newton 24-SEP-06 80000 3 rows selected.
注意点として、データベースの列の値と文字リテラルまたは文字列とを比較する場合に、データベースの列に格納されているデータの大文字と小文字は、デフォルトで、文字列に含まれるデータの大文字と小文字と完全に一致する必要があります。リスト3の問合せからは1行も返されません。従業員の姓を表す文字列の大文字と小文字がEMPLOYEE表のLAST_NAME列に格納されているデータとは異なるからです。 コード・リスト3:WHERE句の条件内で、リテラル値を(大文字と小文字を区別して)使用した問合せ SQL> select first_name, last_name, hire_date, salary 2 from employee 3 where last_name = 'MICHAELS'; no rows selected
文字列のリテラル・データを変換し、データベースの列に格納されているデータの大文字と小文字に一致させる方法(または、その逆の方法)については、このシリーズの今後の記事で取り上げます。 リスト3の例のように、文字列リテラルとデータベースの列の値を比較する場合には、文字列リテラル値を一重引用符で囲む必要があります。日付リテラルをデータベースの列の値と比較する場合にも、このような記述が必要です。 比較する2つの値は同じデータ型である必要があります。数値と数値、文字列と文字列、日付と日付の比較のみを行うようにしてください。Oracle Databaseでは、可能な場合はデータ型の暗黙的変換が実行されますが、一般的にはOracle Databaseでの暗黙的変換が起こらないようにすべきです。リスト4では問合せの結果が返されますが、ベスト・プラクティスとして、数値と文字列の比較は絶対に行わないでください。 コード・リスト4:データ型の暗黙的変換が実行される問合せ SQL> select first_name, last_name, hire_date, salary 2 from employee 3 where salary = '70000'; FIRST_NAME LAST_NAME HIRE_DATE SALARY ----------- ------------- ------------ ----------- Matthew Michaels 16-MAY-07 70000 1 row selected.
包含の範囲値が特定の範囲内に収まる一連のレコード(行)を取得することが必要な場合があります。この操作は、BETWEEN演算子を使用して実行できます(リスト5参照)。 BETWEEN演算子の結果には、その範囲の定義に使用する値自体も含まれます。そのため、リスト5の例では、給与が$80,000(範囲の下限値と上限値の間)の従業員とともに、給与が$75,000(範囲の下限値)の従業員も結果リストに含まれます。BETWEEN演算子は、数値の比較および日付の比較で非常によく使用されます。 コード・リスト5:値の範囲内にあるレコードを選択するための問合せ SQL> select first_name, last_name, salary 2 from employee 3 where salary BETWEEN 75000 and 85000; FIRST_NAME LAST_NAME SALARY ----------- ------------- --------- Frances Newton 75000 Donald Newton 80000 2 rows selected.
大小の比較比較演算子の>、>=、<、<=は、特定の基準よりも上または下にある一連のレコードを取得する必要がある場合に便利です。リスト6では、以下を表す演算子の<=を使用して、年間給与が$80,000以下の従業員のリストを取得します。 コード・リスト6:以下を表す演算子を使用した問合せ SQL> select first_name, last_name, salary 2 from employee 3 where salary <= 80000; FIRST_NAME LAST_NAME SALARY ----------- ------------- --------- Frances Newton 75000 Donald Newton 80000 Matthew Michaels 70000 3 rows selected.
自由なパターンによる検索名前などのデータ値の正しいスペルを知らないか忘れてしまった場合、あるいはデータが壊れている(データベースに不正な値がある)疑いがある場合に、あいまいな検索を実行する必要があります。そのような場合は、LIKE演算子が役に立ちます。この演算子は、ワイルドカード文字を使用したパターン・マッチングを実行します。アンダースコア(_)ワイルドカードは1文字を表し、パーセンテージ(%)ワイルドカードは、0文字を含む任意の数の文字を表します。リスト7の問合せは、姓が大文字のNで始まり、かつ小文字のwを含むレコードを取得します。リスト7の問合せでは、Nとwの間に文字が存在する可能性があり(文字数は不明)、wの後にも文字が存在する可能性があります(文字数は不明)。そのため、この式では2つの%ワイルドカードを使用しています。 コード・リスト7:LIKE演算子を使用し、リテラル文字列とワイルドカードの値を指定した問合せ SQL> select first_name, last_name, salary 2 from employee 3 where last_name like 'N%w%'; FIRST_NAME LAST_NAME SALARY ----------- ------------- --------- Frances Newton 75000 Donald Newton 80000 2 rows selected.
コード・リスト8:LIKE演算子を使用し、ワイルドカードとリテラル値を指定した問合せ SQL> select first_name, last_name 2 from employee 3 where last_name like '__w%'; FIRST_NAME LAST_NAME ----------- ------------- Frances Newton Donald Newton 2 rows selected.
INグループIN演算子は、丸括弧内のカンマ区切りの値のリストを評価します。リスト9の問合せでは、IN演算子を使用して、年間給与が$75,000、$85,000、または$100,000である従業員を取得します。 コード・リスト9:値のリストを含むIN演算子を使用した問合せ SQL> select first_name, last_name, salary 2 from employee 3 where salary in (75000, 85000, 100000); FIRST_NAME LAST_NAME SALARY ----------- ------------- --------- Frances Newton 75000 Emily Eckhardt 100000 2 rows selected.
NOTによる否定BETWEEN、IN、LIKEの比較演算子はすべて、NOTという論理演算子を使用して否定できます(論理演算子については簡単に説明します)。リスト10の問合せを見てみましょう。この問合せは、姓が大文字のNで始まらないすべての従業員を返します。 コード・リスト10:NOT演算子とLIKE演算子を使用した問合せ SQL> select first_name, last_name 2 from employee 3 where last_name NOT LIKE 'N%'; FIRST_NAME LAST_NAME ----------- ------------- Emily Eckhardt Matthew Michaels 2 rows selected.
値が存在すること、または存在しないことこのシリーズのパート1では、値が存在しないことをNULL値と呼ぶことを説明しました。NULL値は別のNULL値や、NULL値以外の値と比較して等しいとも等しくないとも言えません。そのため、データ値がNULLであるかどうかを評価するには、IS NULLまたはIS NOT NULLという比較演算子をかならず使用する必要があります。たとえば、リスト11の問合せは、マネージャーがまだ割り当てられていない従業員を返します。 コード・リスト11:IS NULL演算子を使用した問合せ SQL> select first_name, last_name, manager 2 from employee 3 where manager IS NULL; FIRST_NAME LAST_NAME MANAGER ----------- ------------- ----------------- Frances Newton Emily Eckhardt 2 rows selected.
このシリーズのパート3で説明したDISTINCTキーワードでは、NULL値が認識され返されます。 SQL> select DISTINCT manager 2 from employee; MANAGER ---------- 28 2 rows selected.
SELECT構文のリスト内でDISTINCTキーワードを使用する問合せの結果リストからNULL値を除外するために、WHERE句内でIS NOT NULL演算子を使用できます。 SQL> select DISTINCT manager 2 from employee 3 where manager IS NOT NULL; MANAGER ---------- 28 1 row selected.
ロジック内の真実WHERE句に1つしか条件がないケースはほとんどありません。1つのSQL文の同じWHERE句内に含まれる複数の条件をグループ化するには、論理演算子のANDとORを使用します。条件を追加するたびに、結果セットがさらにフィルタされます。AND演算子を使用して2つの条件を連結した場合、結果に含まれるためには、両方の条件がtrueと評価される必要があります。OR演算子を使用して2つの条件を連結した場合は、一方の条件がtrueと評価されれば結果に含まれます。 たとえば、リスト12のSQL文では、AND論理演算子を使用して2つの比較演算子を連結しています。この結果、(EMPLOYEE表に従えば)マネージャーが割り当てられておらず、かつ給与が$75,000を超える従業員が表示されます。 コード・リスト12:AND論理演算子を使用して複数の条件を連結した問合せ SQL> select first_name, last_name, manager, salary 2 from employee 3 where salary > 75000 4 AND manager IS NULL; FIRST_NAME LAST_NAME MANAGER SALARY ----------- ------------- ----------------- ------ Emily Eckhardt 100000 1 row selected.
ここで、OR論理演算子をAND演算子の代わりに使用すると、リスト13のように、結果セットに別の2行が追加されます。 コード・リスト13:OR論理演算子を使用して複数の条件を連結した問合せ SQL> select first_name, last_name, manager, salary 2 from employee 3 where salary > 75000 4 OR manager IS NULL; FIRST_NAME LAST_NAME MANAGER SALARY ----------- ------------- ----------------- ------ Frances Newton 75000 Emily Eckhardt 100000 Donald Newton 28 80000 3 rows selected.
論理演算子の優先順位WHERE句でANDとORの両方を使用する場合は、常にAND演算子がOR演算子よりも優先されます。つまり、すべてのAND条件が先に評価されます。 リスト14のSQL問合せを見てみましょう。 コード・リスト14:AND論理演算子とOR論理演算子を使用する問合せ SQL> select first_name, last_name, manager, salary 2 from employee 3 where manager IS NULL 4 AND salary = 75000 5 OR salary = 80000; FIRST_NAME LAST_NAME MANAGER SALARY ----------- ------------- ----------------- ------ Frances Newton 75000 Donald Newton 28 80000 2 rows selected.
式を丸括弧で囲んでグループ化すれば、WHERE句内の論理演算子の優先順位を変更できます。リスト15の問合せでは、丸括弧内のOR条件がAND条件よりも先に評価されるため、リスト14とは異なる結果になります。 コード・リスト15:AND論理演算子とOR論理演算子を使用し、丸括弧で優先順位を指定した問合せ SQL> select first_name, last_name, manager, salary 2 from employee 3 where manager IS NULL 4 AND (salary = 75000 5 OR salary = 80000); FIRST_NAME LAST_NAME MANAGER SALARY ----------- ------------- ----------------- ------ Frances Newton 75000 1 row selected.
この新しい問合せで結果に含まれるためには、両方の式、すなわち「マネージャーがNULLである」かつ「給与が$75,000または$80,000である」がtrueと評価される必要があります。Donald Newtonのレコードは2つ目の条件を満たしますが1つ目の条件は満たさないため、この結果セット内に含まれません。 ANDとORが混在する条件を記述する場合は、丸括弧を使用して演算の順序を明示的に指定することを強くお勧めします。一般的には、この方針によってSQLがより理解しやすく、保守しやすく、正確なものになります。 結論WHERE句のない問合せを記述することはほとんどありません。この記事では、単純なSQL SELECT文から発展し、WHERE句を使用して関心のあるデータをフィルタして、より意味のある結果セットを取得する方法について説明しました。比較演算子をWHERE句とともに使用して、必要な結果を指定する方法について確認しました。また、論理演算子を使用して条件をグループ化し、データをさらにフィルタする方法についても確認しました。 このSQLの基礎に関する次回の記事では、SQL文のORDER BY句について説明し、さらにオラクルのSQL*Plusツールについて詳しく見ていきます。
Melanie Caffreyはオラクルの上級開発マネージャーです。Expert PL/SQL Practices for Oracle Developers and DBAs(Apress、2011年)およびExpert Oracle Practices: Oracle Database Administration from the Oak Table(Apress、2010年)の共著者でもあります。 |