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

構文

SELECT [ALL|DISTINCT] {[表名.]列名|順序名.擬似列名|関数} [AS new_column]
[, {[表名.]列名|順序名.擬似列名|関数} [AS new_column] ... ]
FROM [schema.]table|(subquery) [[AS] alias]
   [,[schema.]table|(subquery) [[AS] alias]] ...
[WHERE condition]
[GROUP BY column [,column...]]
[HAVING condition]
[ORDER BY column [,column...] [ASC|DESC]]

SELECT節

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

SELECT [ALL|DISTINCT]
       [table.]column|sequence.column|function|(subquery) [[AS] alias]
     [,[table.]column|sequence.column|function|(subquery) [[AS] alias]] ...
ALL
重複するものを除かずに結果を出力する。
SQL> select all 著者 from 書籍在庫表;
著者
----------
夏目漱石
夏目漱石
夏目漱石
芥川龍之介
芥川龍之介
5レコードが選択されました。

デフォルトの動作は重複するものを除かずに結果を出力する。つまりall句は省略可能である。

DISTINCT
取り出した値の中から重複するものを除いた結果を表示するには、distinctを指定する。
SQL> select distinct 著者 from 書籍在庫表;
著者
----------
夏目漱石
芥川龍之介
2レコードが選択されました。
AS alias
列名を新たにつけるときに指定する。
SELECT deptno, count(*) AS number_of_department FROM employee GROUP BY depno
subquery

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

SEELCT empno, salary, (SELECT AVG(salary) FROM employee) AS avg_salary FROM employee
CONSTRAINT [ constraint_name ] constraint
制約を指定する。

constraint_name には制約の名前を指定する。 constraint_name の指定を省略した場合、自動的に制約名が付けられる。

主キー制約をしていた例を次に示す。

CREATE TABLE department (deptno NUMBER(2) CONSTRAINT pk_dept PRIMARY KEY, deptname VARCHAR2(14))

FROM

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

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

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

table

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

subquery

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

alias
別名を指定する。

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

SELECT * from other.employee

たいていのRDBMSではSELECT文のFROM句を省略できるが、Oracle DatabaseのSELECT文ではFROM句を省略できない。そのため、Oracle DatabaseにはDUALという疑似表が用意されている。擬似列や関数を問い合わせるためFROM句に指定すべき表が無い場合はDUAL表を指定する。

SELECT SYSDATE FROM DUAL

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

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

並び替えに使う列を指定する。

ASC

指定した列を昇順で並び替える。(デフォルト)

DESC

指定した列を降順で並び替える。

SELECT * FROM employee ORDER BY birthdate

射影

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

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';

サブクエリ

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
)

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句を指定できなくなる。

スポンサーリンク