テクノロジー:SQLの基礎

このSQLの基本に関するシリーズ記事のパート4"WHEREはなぜ重要か"(Oracle Magazine、2012年3/4月)では、SQL SELECT文(問合せ)のWHERE句と、データをフィルタすることがいかに重要であるかについて説明しました。WHERE句とSELECT構文のリストにより、SELECT文でどの行を取得するのかをデータベースに指示します。

ソート順序

著者:Melanie Caffrey

リレーショナル・データベースとSQLの基本に関するシリーズ記事のパート5

このSQLの基本に関するシリーズ記事のパート4"WHEREはなぜ重要か"(Oracle Magazine、2012年3/4月)では、SQL SELECT文(問合せ)のWHERE句と、データをフィルタすることがいかに重要であるかについて説明しました。WHERE句とSELECT構文のリストにより、SELECT文でどの行を取得するのかをデータベースに指示します。これで問合せによってフェッチするデータの範囲を絞り込む方法について理解できたので、次にそのデータをソートする順序付ける)方法について学習します。この記事では、SQL ORDER BY句の概要と、特定のオプションやキーワードとともに使用した場合のその動作に焦点を当てて説明します。これらを使用すれば、取得した行をどのようにソートするのかをデータベースに指示できます。

この記事やシリーズの今後の記事の例を試すには、Oracle Databaseインスタンスにアクセスする必要があります。必要に応じて、お使いのオペレーティング・システムに対応したOracle Databaseエディションをダウンロードし、インストールしてください。筆者がインストールをお勧めするエディションは、Oracle Database, Express Editionです。

このOracle Databaseソフトウェアをインストールする場合は、データベースの作成と構成が可能なインストール・オプションを選択してください。サンプルのユーザー・アカウントと関連する新しいスキーマを含む新しいデータベースが作成されます。SQL_101は、このシリーズ記事の例で使用するユーザー・アカウントです。また、データベースの表やその他のオブジェクトが作成されるスキーマでもあります。インストール・プロセスの実行中にスキーマのパスワードを指定するように求められたら、SYSおよびSYSTEMのパスワードを入力して確認し、そのパスワードを覚えておいてください。

このデータベース・ソフトウェアをゼロからインストールした場合でも、既存のOracle Databaseインスタンスにアクセスする場合でも、SQLスクリプトをダウンロードして解凍し、このスクリプトを実行して、SQL_101スキーマ用のサンプルの表を作成します(このスクリプトをテキスト・エディタで開き、スクリプトの実行方法や動作に関する説明を参照してください)。

この記事のSQL問合せは、オラクルのSQL*Plusツールを使用してSQL_101スキーマ内の表に対して実行されます。この記事では、ORDER BY句の説明のほか、SQL*Plusについても詳しく見ていきます。

混乱から秩序を生み出す

Oracle Databaseの表データは、データベースへの挿入時の順序にかかわらず、特定の順序では保管されません。ある列の昇順または降順で行を取得するには、そうするようにデータベースに指示する必要があります。たとえば、すべての従業員を雇用日の順序で表示したい、すべての従業員を年間給与が高い順に表示したい、あるいは会計部門に所属するすべての従業員の姓をアルファベット順に表示したい場合などがあります。ソートされたデータを取得するには、SELECT文にORDER BY句を追加します。ORDER BYはかならず問合せの最終句となります。

リスト1に、結果セットのフィルタも順序付けも行わないEMPLOYEE表の単純な問合せを示します。リスト1とリスト2の結果セットを比較してください。ORDER BY句を使用すると、結果セットはデフォルトで昇順でソートされます。リスト2では、EMPLOYEE表の従業員について、昇順のアルファベット順(デフォルト)で姓をソートした結果が表示されています。

コード・リスト1:EMPLOYEE表のすべての行を表示する単純な問合せ


  
SQL> set linesize 32000
SQL> set feedback on
SQL> select first_name, last_name, hire_date, salary
  2    from employee;

FIRST_NAME            LAST_NAME             HIRE_DATE            SALARY
———————————           —————————————————     ————————————————     ————————
Roger                 Friedli               16-MAY-07             60000
Betsy                 James                 16-MAY-07             60000
Emily                 Eckhardt              07-JUL-04            100000
Frances               Newton                14-SEP-05             75000
Donald                Newton                24-SEP-06             80000
Matthew               Michaels              16-MAY-07             70000

6 rows selected.
 
 

コード・リスト2:姓の昇順のアルファベット順ですべての行を表示する問合せ


  
SQL> select first_name, last_name, hire_date, salary
  2    from employee
  3  ORDER BY last_name;

FIRST_NAME            LAST_NAME             HIRE_DATE            SALARY
———————————           —————————————————     ————————————————     ————————
Emily                 Eckhardt              07-JUL-04            100000
Roger                 Friedli               16-MAY-07             60000
Betsy                 James                 16-MAY-07             60000
Matthew               Michaels              16-MAY-07             70000
Frances               Newton                14-SEP-05             75000
Donald                Newton                24-SEP-06             80000

6 rows selected.
 
 

降順の結果セットを取得するには、ORDER BY句の列名の直後にDESCキーワードを追加します。リスト3の問合せは、雇用日が新しい順にすべての従業員を取得します。ORDER BY句にDESCキーワードがあることに注目してください(ASCキーワードを使用して昇順を明示的に指定することもできますが、昇順がデフォルトであるためこの指定は不要です)。

コード・リスト3:すべての従業員を取得して雇用日の降順で表示する問合せ


  
SQL> select first_name, last_name, hire_date, salary
  2    from employee
  3  ORDER BY hire_date DESC;

FIRST_NAME            LAST_NAME             HIRE_DATE            SALARY
———————————           —————————————————     ————————————————     ————————
Roger                 Friedli               16-MAY-07             60000
Betsy                 James                 16-MAY-07             60000
Matthew               Michaels              16-MAY-07             70000
Donald                Newton                24-SEP-06             80000
Frances               Newton                14-SEP-05             75000
Emily                 Eckhardt              07-JUL-04            100000

6 rows selected.
 
 

名前、番号、配置

ORDER BY句でのデータ順序付けの基準とする列について、明示的に名前を指定する必要はありません。好みに応じて、問合せのSELECT構文のリスト内における列の位置を表す番号を使用できます。リスト4に、すべての従業員を給与が高い順に取得する問合せを示します。この問合せでは、問合せのSELECT構文のリスト内でsalary列の順序番号(4)を使用しています。

コード・リスト4:すべての従業員を取得して4つ目の列の降順で表示する問合せ


  
SQL> select first_name, last_name, hire_date, salary
  2    from employee
  3  ORDER BY 4 DESC;

FIRST_NAME            LAST_NAME             HIRE_DATE            SALARY
———————————           —————————————————     ————————————————     ————————
Emily                 Eckhardt              07-JUL-04            100000
Donald                Newton                24-SEP-06             80000
Frances               Newton                14-SEP-05             75000
Matthew               Michaels              16-MAY-07             70000
Betsy                 James                 16-MAY-07             60000
Roger                 Friedli               16-MAY-07             60000

6 rows selected.
 
 

問合せでは複数の列を基準としてソートすることも可能です。その場合は、複数の昇順、降順の指定を利用します。ORDER BY句に、列(またはSELECT構文のリストにおける列の順序番号)をカンマ区切りで指定します。この結果は、まず1つ目の列、次に2つ目の列という具合に、ORDER BY句に含まれるすべての列によって順序付けられます。結果を降順でソートする場合は、ORDER BY句で該当する列の名前または順序番号の直後にDESCキーワードを使用する必要があります。

リスト5に、すべての従業員を雇用日の降順(新しい順)でソートし、その後さらに給与の低い順、姓の順でソートして表示した結果セットを示します。昇順がデフォルトであるため、リスト5のORDER BY句にある2つ目の列でASCキーワードを指定する必要はありません。同じ理由で、last_name列に関連付けられたASCキーワードも本来は不要です。

コード・リスト5:すべての従業員を取得して、複数のORDER BY基準を使用して表示する問合せ


  
SQL> select first_name, last_name, hire_date, salary
  2    from employee
  3  ORDER BY hire_date DESC, 4, last_name ASC;

FIRST_NAME            LAST_NAME             HIRE_DATE            SALARY
———————————           —————————————————     ————————————————     ————————
Roger                 Friedli               16-MAY-07             60000
Betsy                 James                 16-MAY-07             60000
Matthew               Michaels              16-MAY-07             70000
Donald                Newton                24-SEP-06             80000
Frances               Newton                14-SEP-05             75000
Emily                 Eckhardt              07-JUL-04            100000

6 rows selected.
 
 

設定を確実に行う

ユーザー名とパスワードを入力してデータベースにログインするときには、かならずデータベース内にセッションが作成されます。現在のセッションに関する特定の環境設定については、他の接続中のセッション(ログイン・ユーザー)に影響を与えずに変更できます。リスト1では、SQL文の前にSQL*Plusの各種setコマンドがいくつか登場しています。これらのコマンドは、現在のセッションに関するSQL*Plusの環境設定をカスタマイズするためのシステム変数を設定するものです。たとえば、リスト1では、次のコマンドによりSQL*Plusの1行に表示する文字数を設定しています。この文字数を超えると、新しい行が開始します。


  
set linesize 32000
 
 

このコマンドの短縮表記はset lines nです。このコマンドは、SQL問合せの結果行を折り返さないようにする場合に便利です。

リスト1では、次のsetコマンドも使用されています。


  
set feedback on 
 
 

このコマンドは、結果セット内で返される最終的な行の数を表示するようにSQL*Plusに指示します。このコマンドの短縮表記はset feed onです。

リスト2の結果セットでは、次の最終行が表示されています。


  
6 rows selected. 
 
 

この行が表示されるのは、SQL*Plusのフィードバック設定が(リスト1で)オンになっていたためです。結果セット内で返される最終的な行の数を表示しない場合は、set feed offコマンドを使用してこの設定をオフにできます。

環境設定は、現在のセッションにおけるそれ以降のすべての問合せ実行結果に適用されます。

不明なものの順序付け

すでに説明したとおり、NULL値は不明な値を表します。たとえば、リスト6は、EMPLOYEE表のすべての従業員をmanager値も含めて表示しますが、返された6人のうち2人のレコードについてmanager列がNULL値になっています。

コード・リスト6:すべての従業員をmanager値も含めて表示する問合せ


  
SQL> select employee_id, first_name, last_name, manager
  2    from employee
  3  ORDER BY manager, last_name;

EMPLOYEE_ID FIRST_NAME           LAST_NAME            MANAGER
——————————— ——————————————       ————————————        ——————————
       6567 Roger                Friedli                   28
       6568 Betsy                James                     28
       7895 Matthew              Michaels                  28
       1234 Donald               Newton                    28
         28 Emily                Eckhardt
         37 Frances              Newton

6 rows selected.
 
 

ORDER BY句により結果が昇順でソートされる場合、NULL値はデフォルトで最後に表示されます。逆に、リスト7のように、ORDER BY句でNULL値を含む列の降順を指定した場合は、NULL値はデフォルトで最初に表示されます。ORDER BY句でNULLS FIRSTオプションまたはNULLS LASTオプションを使用することで、このデフォルトの動作をオーバーライドし、NULL値のソート方法を明示的に指定できます。リスト8の例では、NULLS FIRSTオプションを使用して、NULL値を最後に表示するというORDER BY句のデフォルト動作をオーバーライドしています。

コード・リスト7:NULL値を含む列を降順で順序付ける問合せ


  
SQL> select employee_id, first_name, last_name, manager
  2    from employee
  3  ORDER BY manager DESC, last_name;

EMPLOYEE_ID FIRST_NAME           LAST_NAME            MANAGER
——————————— ——————————————       ————————————        ——————————
         28 Emily                Eckhardt
         37 Frances              Newton
       6567 Roger                Friedli                   28
       6568 Betsy                James                     28
       7895 Matthew              Michaels                  28
       1234 Donald               Newton                    28

6 rows selected.
 
 

コード・リスト8:NULLS FIRSTオプションを使用してNULL値を含む列を順序付ける問合せ


  
SQL> select employee_id, first_name, last_name, manager
  2    from employee
  3  ORDER BY manager NULLS FIRST, last_name;

EMPLOYEE_ID FIRST_NAME           LAST_NAME            MANAGER
——————————— ——————————————       ————————————        ——————————
         28 Emily                Eckhardt
         37 Frances              Newton
       6567 Roger                Friedli                   28
       6568 Betsy                James                     28
       7895 Matthew              Michaels                  28
       1234 Donald               Newton                    28

6 rows selected.
 
 

重複を除外してソート

SQL SELECT文にORDER BY句を含める場合、通常は文のSELECT構文のリスト内にある列または式によってソートするように指定します。一方、SELECT構文のリストにない列や式によって順序付けることもできます。リスト9では、雇用日が新しい順に順序付けて、次にその中で姓をアルファベット順でソートした従業員のリストを表示します。このソートや表示は正しく実行されますが、hire_dateがSELECT構文のリストにないため、従業員の名と姓だけが出力されます。

コード・リスト9:SELECT構文のリストに含まれない列によって順序付ける問合せ


  
SQL> select first_name, last_name
  2    from employee
  3  ORDER BY hire_date DESC, last_name;

FIRST_NAME                     LAST_NAME
————————————                   ————————————— 
Roger                          Friedli
Betsy                          James
Matthew                        Michaels
Donald                         Newton
Frances                        Newton
Emily                          Eckhardt

6 rows selected.
 
 

SELECT構文のリストにDISTINCTキーワードが含まれる場合、ORDER BY句に含めることができるのは、そのSELECT構文のリストにある列または式だけです。リスト10のように、DISTINCTキーワードを使用する問合せで、SELECT構文のリストに含まれない列で順序付けしようとするとエラーが発生します。

コード・リスト10:ORDER BYの列がSELECT構文のリストにないためにエラーが発生するDISTINCTを指定した問合せ


  
SQL> select DISTINCT hire_date
  2    from employee
  3  ORDER BY manager NULLS FIRST;
ORDER BY manager NULLS FIRST
         *
ERROR at line 3:
ORA-01791: not a SELECTed expression
 
 

記述の誤り

SQL文の記述方法を学習している間はかならずミスをします。Oracle Databaseから受け取るエラー・メッセージを解釈できるかが、SQLの理解の鍵となります。エラー・メッセージには、誤りの内容を理解しやすいものもあれば、それほど単純ではないものもあります。最善策は、エラー・メッセージを一度に1つずつ解決していくことです(これはデバッグと呼ばれるプロセスです)。

Oracle Databaseでは、問合せの何行目でエラーが発生したかが示されます。たとえば、リスト10では次のエラー・メッセージが表示されます。


  
ERROR at line 3:
ORA-01791: not a SELECTed expression
 
 

このメッセージにより、このデータベース・プログラムには次の行に問題があることがわかります。


  
3  ORDER BY manager NULLS FIRST; 
 
 

次のステップ

リレーショナル・データベースの設計と概念に関する詳細の確認

Oracle Database概要11gリリース2 (11.2)

Oracle® Database SQL 言語リファレンス11g リリース1(11.1)

その他の記事 SQLの基礎、パート1~4

ダウンロード  この記事のスクリプト

エラー・メッセージが示すとおりに問合せのSELECT構文のリストにMANAGER列を追加すれば、(この問合せに他のエラーがないと仮定すると)この文の再実行が成功するようになります。

SQLの学習中に起こるもっとも一般的なエラーはおそらく構文エラーです。デバッグ中にSQL文を入念に読み込むこと(そして何度も読み込むこと)がいかに重要であるかは言うまでもありません。よくある例をいくつか挙げると、単純なタイプミス、カンマの位置の間違いやカンマの書き忘れ、一重引用符の片方の書き忘れなどがありますが、これらの誤りが、解決策が簡単にはわからないような無数の問題につながる可能性があります。

別名と書式モデルの使用

問合せの出力について、特定の列や式に対してわかりやすい見出しを付けて表示したい場合があります。このような見出しは、SQL文のSELECT構文のリスト内の列または式に列の別名を追加することで表示できます。使用できる列の別名の種類について、リスト11に例を示します。列の別名が複数の語で構成される場合、もしくは大文字と小文字を指定したとおりに表示したい場合(指定しない場合のデフォルトは大文字)は、別名を二重引用符で囲む必要があります。リスト11のように、SELECT構文のリストで二重引用符で囲まれていない列の別名については、問合せのORDER BY句でも使用できます。

コード・リスト11:列の別名を使用する問合せ


  
SQL> select first_name first, last_name "Last", hire_date "Start Dt", salary "sal"
  2    from employee
  3  ORDER BY manager NULLS FIRST, first;

FIRST                 Last                  Start Dt                sal
——————————            —————————————————     —————————————        ————————
Emily                 Eckhardt              07-JUL-04            100000
Frances               Newton                14-SEP-05             75000
Betsy                 James                 16-MAY-07             60000
Donald                Newton                24-SEP-06             80000
Matthew               Michaels              16-MAY-07             70000
Roger                 Friedli               16-MAY-07             60000

6 rows selected.
 
 

SQL*Plusには、結果セットの列の属性を書式設定できる書式設定コマンドが備わっています。たとえば、リスト12は、書式モデル書式マスクとも呼ばれる)をSALARY列に適用した使用例です。この種の書式設定コマンドは、NUMBERデータ型で構成される任意のSELECT構文のリストの式に適用できます。このSQL*PlusのCOLUMNコマンドの短縮表記はCOLです。

コード・リスト12:COLUMNコマンドによってSQL*Plus書式モデルを使用する問合せ


  
SQL> COLUMN salary FORMAT $999,999
SQL> select first_name, last_name, hire_date, salary
  2    from employee
  3  order by salary desc, last_name;

FIRST_NAME            LAST_NAME             HIRE_DATE             SALARY
———————————           ————————————————      ————————————————    ————————————
Emily                 Eckhardt              07-JUL-04           $100,000
Donald                Newton                24-SEP-06            $80,000
Frances               Newton                14-SEP-05            $75,000
Matthew               Michaels              16-MAY-07            $70,000
Roger                 Friedli               16-MAY-07            $60,000
Betsy                 James                 16-MAY-07            $60,000

6 rows selected. 
 
 

SQL*PlusでのSQL文

SQL*Plusでは、SQL文の実行時点を指示するための文の終了記号を使用する必要があります。このシリーズ記事ではこれまで、ほとんどの例でセミコロン(;)を文の終了記号として使用してきました。代わりに、スラッシュ(/)を文の終了記号として使用することもできます。ただし、SQL文のそれ以外の部分から改行して別の行で使用する必要があります。リスト13に、許容される2つの終了記号の使用方法を示します。

コード・リスト13:セミコロンおよびスラッシュの終了記号を使用して実行した問合せ


  
SQL> select first_name, last_name, hire_date, salary
  2    from employee
  3  order by hire_date desc, salary desc, last_name;

FIRST_NAME            LAST_NAME             HIRE_DATE             SALARY
———————————           ————————————————      ————————————————    ————————————
Matthew               Michaels              16-MAY-07            $70,000
Roger                 Friedli               16-MAY-07            $60,000
Betsy                 James                 16-MAY-07            $60,000
Donald                Newton                24-SEP-06            $80,000
Frances               Newton                14-SEP-05            $75,000
Emily                 Eckhardt              07-JUL-04           $100,000

6 rows selected.

SQL> select first_name, last_name, hire_date, salary
  2    from employee
  3  order by hire_date desc, salary desc, last_name
  4  /

FIRST_NAME            LAST_NAME             HIRE_DATE             SALARY
———————————           ————————————————      ————————————————    ————————————
Matthew               Michaels              16-MAY-07            $70,000
Roger                 Friedli               16-MAY-07            $60,000
Betsy                 James                 16-MAY-07            $60,000
Donald                Newton                24-SEP-06            $80,000
Frances               Newton                14-SEP-05            $75,000
Emily                 Eckhardt              07-JUL-04           $100,000

6 rows selected.
 
 

SQL*Plusバッファでは、実行した直前の文が保持されます。その文を再入力せずにもう一度実行するには、スラッシュを入力して[Enter]を押します。このショートカットは、特定の表へのレコードの挿入や更新を行う予定のバッチ・ジョブのステータスをチェックする場合などに便利です。

最新の文のみがバッファに残り、別の問合せを実行すればすぐにバッファの文がその問合せに置き換えられます。バッファの内容を表示する(リストする)ために、SQL*PlusのLISTコマンド(またはlという文字のみ)を実行できます。たとえば、次のようになります。


  
SQL> l
  1  select first_name, last_name, hire_date, salary
  2    from employee
  3* order by hire_date desc, salary desc, last_name
SQL>
 
 

結論

この記事では、単純なSQL SELECT文から発展し、ORDER BY句を使用して、表示するデータをより意味のあるように順序付ける方法について説明しました。DESC、NULLS FIRST、NULLS LASTの各オプションの作用や、ORDER BY句でのデフォルトのNULL値の処理方法について確認しました。また、SELECT構文のリストにない列がORDER BY句に含まれている場合に、SELECT構文のリストでのDISTINCTキーワードの有無によって問合せの実行がどのように影響を受けるかについても確認しました。

このSQLの基礎に関するシリーズの次回の記事では、文字関数について見ていきます。

Melanie Caffreyの顔写真

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年)の共著者でもあります。