SQL SELECT 文

SQLのSELECT文は、1つ以上の表からデータを取得します。取得されたデータは、結果表または問合せ結果と呼ばれる表の形式で表示されます。

すべての列

社員テーブル(emp)からすべての列を取得する。

SELECT * FROM emp

指定した列

社員テーブルから社員番号(empno)と社員名(ename)を取得する。

SELECT empno, ename FROM emp

重複する値の除外

SQLのSELECT文で重複する値を除外するには、DISTINCT句を指定する。

社員テーブルから上司の社員番号(mgr)を取得する。ただし、重複する値は除外する。

SELECT DISTINCT mgr FROM emp

列に別名をつける

SQLのSELECT文でAS句を使うと、カラム(列)に別名を付けることができる。

使い方は、列名の後にAS句で別名を指定する。日本語の別名をつけることもできる。

SELECT empno AS 社員番号, ename AS 氏名 FROM emp

ASを省略して、列名の後に別名を指定してもよい。

SELECT empno 社員番号, ename 氏名 FROM emp

件数の取得

SQLのSELECT文でレコード件数を取得するには、COUNT関数を使う。

社員テーブルのレコード件数を取得する。

SELECT COUNT(*) FROM emp

件数指定

MySQLやPostgreSQLではSELECT文の件数指定にLIMIT句を指定できるが、OracleのSELECT文にLIMIT句は指定できない。

OracleのSELECT文で取得する件数の上限を指定するには、ROWNUM疑似列を条件に指定する。

SELECT sal FROM emp WHERE ROWNUM <= 10

SELECT文は結果を順不同で返すため、上記のSELECT文はランダムに10件までを取得する。

何らかの条件で並び替えるには、SELECT文にORDER BY句を指定する。ただし、ORDER BY句による並び替えは、結果を取得してから並び替えるため、次のSELECT文はランダムに10件までを取得することになる。

SELECT sal FROM emp WHERE ROWNUM <= 10 ORDER BY sal DESC

何らかの条件で並び替えてから最大10件までを取得するには、副問い合わせを利用する。

SELECT sal FROM (SELECT sal FROM emp ORDER BY sal DESC) WHERE ROWNUM <= 10

別スキーマ

販売スキーマ(sales)にある顧客テーブル(customer)からすべての列を取得する。

SELECT * FROM sales.customer

条件

SQLのSELECT文で条件をつけるには、WHERE句を指定する。

社員テーブルから社員番号が1001であるレコードを取得する。

SELECT empno, ename FROM emp WHERE empno = 5389
EMPNO ENAME
5389 井上和

シーケンス

シーケンスから次の値を取得する。

SELECT empno_seq.NEXTVAL FROM DUAL

SELECT節

列名 には取り出す列の名前を指定します。全ての列を取り出すにはアスタリク記号を指定します。

SELECT [ALL|DISTINCT]
     [table.]column|sequence.column|function|(subquery) [[AS] alias]
   [,[table.]column|sequence.column|function|(subquery) [[AS] alias]] ...
subquery

サブクエリ(副問い合わせ)を指定する。

FROM

SELECT文のFROM節には、問合せ先となる表、ビュー、シノニム又は副問合せを指定する。カンマで区切って複数指定することができる。

FROM [schema.]table|(subquery) [[AS] alias]
 [,[schema.]table|(subquery) [[AS] alias]] ...
schema

テーブル、ビュー又はシノニムのスキーマ名を指定する。 schema の指定を省略した場合は自スキーマとみなされる。

table

テーブル名、ビュー名又はシノニム名を指定する。

subquery

副問合せ(サブクエリ)を指定する。

alias
別名を指定する。

現在のスキーマと異なるスキーマにある表を指定する場合は、表名の前にスキーマ名とピリオド(ドット)を付ける。

SELECT * from other.employee

WHERE

WHERE句には選択する行の条件を指定する。条件の指定を省略した場合は、すべての行が選択される。条件に当てはまる行が無かった場合は、何も結果は返らない。条件は比較演算子を使う。複数の条件を論理演算子で繋ぐこともできる。

副問合せを使って、倉島颯良と同じ部署の社員の名前を問い合わせる。

SELECT ename FROM emp WHERE deptno = (SELECT deptno FROM emp WHERE ename = '倉島颯良');

職種と部署が倉島颯良と同じ社員の名前を問い合わせる。

SELECT ename FROM emp WHERE (job, deptno) = (SELECT job, deptno FROM emp WHERE ename = '倉島颯良');

GROUP BY

複数の行を条件ごとにまとめて扱うときに指定する。

SELECT AVG(salary) GROUP BY deptno FROM employee

複数の列でグループ化することもできる。

SELECT deptno, secno, COUNT(*) AS 人数 GROUP BY by deptno, secno FROM employee

HAVING

グループ関数の結果に対して条件を付けるには、HAVING句を使用する。

SELECT COUNT(*) AS number FROM employee WHERE deptno > 10 GROUP BY deptno HAVING COUNT(*) >= 10;

ORDER BY

SQLのSELECT文で表(テーブル)を問い合わせたときに返る行(レコード)の順序は不定であり、どのような順序で返されるかは保証されていない。何らかの法則があるかのように見えても、それは誤解である。たとえば、SELECT文による問い合わせで返った行の順序がINSERT文で挿入した順番のように見えたとしても、それは偶然である。

SELECT文の問い合わせで返る行の順序を指定するには、ORDER BY句を使用する。指定した列の値で昇順に並び替えられる。降順に並び替えるにはDESCを指定する。ORDER BY句を省略した場合は、並び替えられない。DESC句を指定すると、降順に並び替えられる。

構文

ORDER BY column [ASC|DESC] [,column [ASC|DESC]]...
column
並び替えに使う列を指定する。
SELECT ename, hiredate FROM emp ORDER BY hiredate
ENAME HIREDATE
鈴木絢音 13-03-28
梅澤美波 16-09-04
賀喜遥香 18-12-03
井上和 22-02-01
ASC
指定した列を昇順で並び替える。(デフォルト)
SELECT ename, hiredate FROM emp ORDER BY hiredate ASC
DESC
指定した列を降順で並び替える。
SELECT ename, hiredate FROM emp ORDER BY hiredate DESC
ENAME HIREDATE
井上和 22-02-01
賀喜遥香 18-12-03
梅澤美波 16-09-04
鈴木絢音 13-03-28

射影

射影とは、表から特定の列を抽出することである。

student表からstudent_name列を抽出する例を次に示す。

student
student_no student_name club_no
1 堀内 まり菜 1
2 飯田 來麗
3 杉崎 寧々 2
4 佐藤 日向 1
SELECT student_name FROM student

選択

選択とは、表から特定の行を抽出ことである。

student表からstudent_noが1である行を抽出する例を次に示す。

SELECT * FROM student WHERE student_no = 1

結合

結合とは、複数の表からひとつの結果表を作成することである。結合には内部結合と外部結合の2種類がある。

内部結合

内部結合(単純結合)とは、結合条件を満たす行のみを戻す、複数の表の結合である。たとえば次の2つの表があったとする。

employee
empno empname deptno
1 堀内まり菜 1
2 飯田來麗 2
3 杉崎寧々 (NULL)
4 佐藤日向 1
department
deptno deptname
1 総務部
2 営業部
3 開発部
SELECT * FROM employee, department WHERE employee.deptno = department.deptno

上記のSQLで得られる結果は次のとおり。

結果表
empno empname deptno deptno deptname
1 堀内まり菜 1 1 総務部
2 飯田來麗 2 2 営業部
4 佐藤日向 1 1 総務部

empnoが3の行はdeptno列がNULLであり、department表と一致する行がない。したがって結合条件を満たさないため、内部結合の結果には含まれない。

内部結合を行うSQLの記述方法には2通りある。

  1. WHERE句に結合条件を記述
  2. INNER JOIN句に結合条件を記述

INNER JOIN句の書式を次に示す。

table1 [INNER] JOIN table2 ON table1.column = table2.column
table1 [INNER] JOIN table2 USING (column [,column...])

WHERE句に結合条件を記述する例を次に示す。

SELECT * FROM employee, department WHERE employee.deptno = department.deptno

INNER JOIN句に結合条件を記述する例を次に示す。

SELECT * FROM employee INNER JOIN department ON (employee.deptno = department.deptno)

外部結合

外部結合は、結合条件を満たす行に加えて、一方の表については結合条件を満たさない行も戻す、複数の表の結合である。たとえば次の2つの表があったとする。

employee
empno empname deptno
1 堀内まり菜 1
2 飯田來麗 2
3 杉崎寧々 (NULL)
4 佐藤日向 1
department
deptno deptname
1 総務部
2 営業部
3 開発部

上記2つの表を外部結合(LEFT OUTER JOIN)するSQL文は次のようになる。

SELECT * FROM employee LEFT OUTER JOIN department ON employee.deptno = department.deptno

上記のSQLで得られる結果は次のとおり。

empno empname deptno deptno deptname
1 堀内まり菜 1 1 総務部
2 飯田來麗 2 2 営業部
3 杉崎寧々 (NULL) (NULL) (NULL)
4 佐藤日向 1 1 総務部

empnoが3の行はdeptno列がNULLであり、department表と一致する行がないが、外部結合(LEFT OUTER JOIN)の結果にも含まれる。

table1 {LEFT|RIGHT} [OUTER] JOIN table2 ON table1.column = table2.column
table1 {LEFT|RIGHT} [OUTER] JOIN table2 USING (column [,column...])

表AおよびBの外部結合を行い、すべての行をAから戻す問合せ(左側外部結合)を記述するSQL文の例を次に示す。

FROM 表A LEFT OUTER JOIN 表B ON (表A.列1 = 表B.列1)

上記のSQL文は、WHERE句の結合条件で外部結合演算子(+)をBの列に適用する方法でも可能である。

FROM 表A, 表B WHERE 表A.列1 = 表B.列1(+)

表AおよびBの外部結合を行い、すべての行をBから戻す問合せ(右側外部結合)を記述するSQL文の例を次に示す。

FROM 表A RIGHT OUTER JOIN 表B ON (表A.列1 = 表B.列1)

上記のSQL文は、WHERE句の結合条件で外部結合演算子(+)をAの列に適用する方法でも可能である。

FROM 表A, 表B WHERE 表A.列1(+) = 表B.列1

内部結合の場合、WHERE節に選択条件を記述できる。

SELECT *
FROM table1
JOIN table2 ON table1.key = table2.key
WHERE table1.delete_flag = '0' AND table2.delete_flag = '0';

外部結合の場合、結合するレコードが無いときは列がNULLになるので、WHERE節ではなく、JOIN節に条件を記述する。

SELECT *
FROM table1
LEFT OUTER JOIN table2 ON table1.key = table2.key AND table2.delete_flag = '0'
WHERE table1.delete_flag = '0';

FOR UPDATE

SELECT文にFOR UPDATE句を指定すると、行(レコード)レベルでロックを獲得する。ロックを獲得した行は、他のトランザクションから更新又は削除されることを防ぐことができる。コミット又はロールバックを行うことで、ロックは解放される。

SELECT ... FOR UPDATE [OF [
  表名 .]
  列名 [, ...]] [WAIT [n_sec] | NOWAIT]

テーブルを結合している場合(SELECT文のFROM句に複数のテーブルを指定している場合)、FOR UPDATE OF句でロックするテーブルを限定することができる。OF句に指定するのは列名であるが、ロックは列単位ではなく行単位である。

条件に一致するレコードが表にあれば更新、なければ挿入(新規追加)する場合、普通にSELECTしてレコードが無かったらUPDATEするという方法では、SELECT時にレコードが存在してもUPDATE時にそのレコードがまだ存在している保証はない。そこで、SELECT FOR UPDATEを使うと、レコードロックがかかり、UPDATEするまで削除されない。なお、SELECT FOR UPDATEを実行した場合、コミットするまでロックされたままなので注意が必要である。Oracle 9i以降ではMERGE文を使用するのが望ましい。

行が一意に特定できなくなる操作にはFOR UPDATE句を使用できない。

UNION

UNIONを使うことにより、複数のSELECT分をつなげてひとつの分として実行することができる。

SELECT文1 UNION [ALL]
  SELECT文2 [UNON [ALL]
  SELECT文3 ] ...

複数のSELECT結果で重複する行がある場合、それらは1行にまとめられる。重複する行をまとめずにすべての行を得たい場合は、ALL句を指定する。

UNIONでつなげるすべてのSELECT文の選択列は数、型ともに同じにする必要がある。

ORDER BY句でソートすることもできるが、ORDER BY句は最後のSELECT文に記述する。

UNIONを利用した場合、SELECT文にFOR UPDATE句を指定できなくなる。

FROMに指定する表がないとき

たいていのRDBMSではSELECT文のFROM句を省略できるが、OracleデータベースのSELECT文ではFROM句を省略できない。そのため、DUALという疑似表が用意されている。

擬似列や関数を問い合わせるためFROM句に指定すべき表が無い場合は、DUALを指定する。

select SYSDATE from DUAL
select empno_sequence.CURRVAL from DUAL

MySQLのSELECT文はFROM節を省略することができるため、DUALのようなダミーテーブルを使う必要がない。ただし、互換性のために FROM DUAL と記述することができる。

SELECT句のサブクエリ

SELECT文のSELECT句にサブクエリを指定することができる。

SELECT empno, salary, (SELECT AVG(salary) FROM emp) AS avg_salary FROM emp

WHERE句のサブクエリ

SELECT及びINSERT、UPDATE、DELETEのWHERE句にサブクエリを指定することができる。

examテーブル
student day score
堀内まり菜 2012-03-31 40
堀内まり菜 2013-03-31 70
飯田來麗 2012-03-31 80

examテーブルからstudent毎のdayが最大の行を抽出するSQLは次のとおり。

SELECT student, day, score
FROM exam e1
WHERE e1.day = (
  SELECT MAX(day)
  FROM exam e2
  WHERE e1.student = e2.student
)

上記のサブクエリを使ったSQLは、次のようにJOINでも実現できる。

SELECT e1.student, e1.day, e1.score
FROM exam e1 JOIN exam e2 ON (e1.student = e2.student)
GROUP BY e1.student, e1.day, e1.score
HAVING e1.day = MAX(e2.day)

相関サブクエリ

相関サブクエリ(相関副問い合わせ)とは、外側クエリのテーブルを参照するサブクエリである。相関サブクエリのサンプルを示す。

SELECT * FROM table1 t1 WHERE 1 IN (
SELECT foo FROM table2 t2 WHERE t1.id = t2.id
)

関連SQL