SELECTステートメントは、1つもしくは複数のテーブルから、WHERE句などを併用し、データを抽出する、SQLにおけるデータ操作言語 (DML)ステートメントの1つである。
これは、データベースの1つもしくは複数のテーブルからデータを抽出するための命令で、データ操作言語 (DML)の中では最もよく使用される。プログラマはどのような結果を欲しいのかをSQL文で記述する必要はあるが、その結果を取得するためにどのような物理的な操作が実行されるのかを指示する必要はなく、データベースシステム(クエリオプティマイザ)がそのSQL文から最適なクエリプラン(実行計画)を作成する。
これらは、ANSI(米国規格協会)によってある程度は標準化されているが、それ以外に製品固有の命令文が多数存在するため、使用するには各種DBMSの仕様とバージョンを確認する必要がある。
なお、「テーブル」は「表」、「行」は「レコード」、「列」は「項目」と呼ぶこともある。
SELECT [ALL | DISTINCT] 列名 [,列名...]
FROM テーブル名 [,テーブル名...]
[WHERE 条件式]
[GROUP BY 列名 [HAVING 条件式]]
[ORDER BY 列名]
GROUP BY 列名[,列名...]
ORDER BY 列名[,列名...]
SELECT文において必須の構成句である。指定列を記述することで、列を射影する。*で全列表示できる。また、算術演算子やグループ関数が使用可能である。
列名 [AS] 列別名
SELECT 商品名,COUNT(販売個数) FROM 販売実績 GROUP BY 商品名
COUNT(*)とすると、NULL値を含めた全ての行数を返すが、COUNT(列名)とした場合、NULL値は返さない。SELECT文において必須の構成句。FROM句では列参照に用いる表を指定する。複数の表から指定する場合、結合が行われ、JOINを用いるほか、WHERE句によって共通列の結合関係を指定することも可能(ただし、この場合は外部結合ができない。ただし、OracleDBMSの場合、(+)という特殊な記号を使用して、外部結合を行える)。なお、表を必要としないクエリを行う場合も、DUAL表のようなダミーの表を指定することとなるが、このような場合にFROMを省略できる拡張の行われた処理系も多く存在する。
このFROM句では表別名の指定が可能であるが、一旦表別名を指定した場合、表別名で記述してやらないとエラーになる。
複数の表から行を参照する場合に用い、JOINを利用することが多い。種類としては以下のものがある。
SELECT 任意の表名.共通列 FROM 表名A [INNER] JOIN 表名B ON 表名A.共通列 = 表名B.共通列;
SELECT 共通列A,任意の表名.共通列B,その他の列名 FROM 表名A [INNER] JOIN 表名B USING(共通列A);
SELECT 任意の表名.共通列 FROM 表名A [INNER] JOIN 表名B ON 表名A.共通列 <> 表名B.共通列;
SELECT 企業名,業種名 FROM 企業 NATURAL JOIN 業種;
SELECT K.棋士名, S.棋士名 AS 師匠名 FROM 表名A K [INNER] JOIN 表名A S ON 表名K.師匠番号 = 表名S.棋士番号;
SELECT 任意の表名.共通列 FROM 表名A (方向) [OUTER] JOIN 表名B ON 表名A.共通列 = 表名B.共通列;
WHERE句は、データを抽出する選択条件式を指定する。単一式を用いるほか、複数条件を照会する副問合せが用いられることも多い。また、テーブル間結合を行う際には、その結合関係を指定する。このWHERE句ではグループ関数を使用してはいけないルールが存在する。
GROUP BY句は、グループ化する列名または列名を含んだ式を指定する。列別名は使用できない。また、SELECT文でGROUP BY句で、グループ関数を除き、グループ化する列以外の列が存在した場合、一緒に記述する必要がある。
例: SELECT A. B FROM LIST GROUP BY A, B;
(グループ化するのはAだが、B列も一緒に記述しないとエラーとなる)。
また、GROUP BY句を含むとビューの作成ができない(SELECT文でグループ関数を使用した場合、あるいはDISTINCT句を使用した場合も同じ)。
HAVING句は、GROUP BY句で集計した結果に対して抽出条件を指定する際に使用する。グループ関数の使用が可能である。順序はGROUP BY句と前後になっても問題ない。
ORDER BY句は、ソートする列または列を含んだ式を指定するもので、いかなる場合でも構文の最後に指定する。カンマで区切ることで、複数列を指定できる。通常はASC(ascending order)、すなわち昇順指定であり、降順指定したい場合はDESC(descending order)と表記する。また、列別名での指定が可能なほか、序数での指定が可能である(たとえば、2番目の列で参照したい場合、ORDER BY 2とできる)。
ここでのNULLはDBMSに依存し、最大値をとるものと最小値をとるものがある。
副問合せは値が一定でない値に対して問合わせが可能であり、必ず( )で囲む必要がある。FROM句、WHERE句、HAVING句で使用可能。FROM句で指定されていない別表を参照することも可能であり、また、ネストにも制限はない(ただし、パフォーマンスは低下するおそれがある)。
副問合せに対して単一行を選択したい場合は比較演算子を用いる。この場合、複数行が検索されればエラーとなる。もし、複数行を選択したい場合は、一般にIN、他にANY(SOME)+比較演算子、ALL+比較演算子、またはEXISTSを用いる。いずれの式も頭にNOTを付記すれば、否定表現となる。この比較条件の記述はDBMSの環境に依存していることが多い。
SELECT 商品名 FROM 商品 WHERE 商品番号 IN (3,8)
と簡潔に表すことができる。これを副問合せに応用することも可能で、たとえば納品(伝票番号,行番号,商品番号,納品日,個数,…)という表から一度でも納品された商品を表したい場合は
SELECT 商品名 FROM 商品 WHERE 商品番号 IN (SELECT 商品番号 FROM 納品)
とすれば、一度でも納品された商品が抽出される。逆に、NOT INとすると納品表に一度も納品されていない商品が抽出される。
SELECT 商品名 FROM 商品 WHERE EXISTS (SELECT * FROM 納品 WHERE 商品.商品番号 = 納品.商品番号)
どちらで記述しても結果は同じだが、実行順序は異なっている。通常、副問合せを先に実行しその結果を使って主問合せを実行するが、EXISTSの例の場合、副問合せ内で副問合せ内にない表(商品表)を参照しているので副問合せを先に実行できない。このように、そのFROM句にない表の列を参照する副問合せを「相関副問合せ」と言い、その場合は、主問合せの表の行ごとに副問合せが繰り返し実行される。INとEXISTSでは実行順序が異なるためパフォーマンスに差が出ることがある。副問合せの結果サイズが大きい場合はEXISTSの方が高速である。ただし最近のデータベースのクエリオプティマイザは、INとEXISTSを内部的に同じような実行計画に変換することがあり、パフォーマンスに大きな差が出ない場合も多い。
MySQL、PostgreSQLなど一部のDBMSで使用可能な構成句。ORDER句の後に記述すると、選択する行を限定できる。文法はLIMIT(開始の行,取得する行数)、またはLIMIT 取得する行数 OFFSET 開始の行。たとえば、受験者(生徒番号,生徒名,国語,数学,英語)という表から高得点者上位10人だけを抽出したい場合は以下のように記述する(国語、数学、英語には数値が入る)。
SELECT 生徒名,SUM(国語+数学+英語) AS 成績 FROM 生徒 ORDER BY 成績 DESC LIMIT 1 , 10
| テーブル "T" | SQL文 | 結果 | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
SELECT * FROM T; |
| ||||||||||||
|
SELECT C1 FROM T; |
| ||||||||||||
|
SELECT * FROM T WHERE C1 = 1; |
| ||||||||||||
|
SELECT * FROM T ORDER BY C1 DESC; |
|
右図のテーブル"T"欄のテーブルに対して、SQL文 SELECT * FROM T; を実行すると、結果欄に示されているように、テーブル"T"のすべての行とすべての列が返される。
同じテーブル"T"に対して、SQL文 SELECT C1 FROM T; を実行すると、テーブル"T"のすべての行の列C1のみが返される。これは、関係代数 における「射影」に相当する。
同じテーブル"T"に対して、SQL文 SELECT * FROM T WHERE C1 = 1; を実行すると、列C1 の値が 1 であるすべて行のすべての列が返される。これは、関係代数 における「選択」に相当する。
最後のSQL文 SELECT * FROM T ORDER BY C1 DESC; は最初のSQL文と同じ行を返すが、並び順が、ORDER BY句により、C1に対して降順(Z-A)になる。ORDER BY句で複数列を指定する場合は、カンマで区切る。例:ORDER BY C1 ASC, C2 DESC(この場合、列C1に対しては昇順、列C2に対しては降順になる。)