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 [ALL|DISTINCT] [table.]column|sequence.column|function|(subquery) [[AS] alias] [,[table.]column|sequence.column|function|(subquery) [[AS] alias]] ...
サブクエリ(副問い合わせ)を指定する。
SELECT文のFROM節には、問合せ先となる表、ビュー、シノニム又は副問合せを指定する。カンマで区切って複数指定することができる。
FROM [schema.]table|(subquery) [[AS] alias]
[,[schema.]table|(subquery) [[AS] alias]] ...
テーブル、ビュー又はシノニムのスキーマ名を指定する。 schema の指定を省略した場合は自スキーマとみなされる。
テーブル名、ビュー名又はシノニム名を指定する。
副問合せ(サブクエリ)を指定する。
現在のスキーマと異なるスキーマにある表を指定する場合は、表名の前にスキーマ名とピリオド(ドット)を付ける。
SELECT * from other.employee
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 = '倉島颯良');
複数の行を条件ごとにまとめて扱うときに指定する。
SELECT AVG(salary) GROUP BY deptno FROM employee
複数の列でグループ化することもできる。
SELECT deptno, secno, COUNT(*) AS 人数 GROUP BY by deptno, secno FROM employee
グループ関数の結果に対して条件を付けるには、HAVING句を使用する。
SELECT COUNT(*) AS number FROM employee WHERE deptno > 10 GROUP BY deptno HAVING COUNT(*) >= 10;
SQLのSELECT文で表(テーブル)を問い合わせたときに返る行(レコード)の順序は不定であり、どのような順序で返されるかは保証されていない。何らかの法則があるかのように見えても、それは誤解である。たとえば、SELECT文による問い合わせで返った行の順序がINSERT文で挿入した順番のように見えたとしても、それは偶然である。
SELECT文の問い合わせで返る行の順序を指定するには、ORDER BY句を使用する。指定した列の値で昇順に並び替えられる。降順に並び替えるにはDESCを指定する。ORDER BY句を省略した場合は、並び替えられない。DESC句を指定すると、降順に並び替えられる。
ORDER BY column [ASC|DESC] [,column [ASC|DESC]]...
SELECT ename, hiredate FROM emp ORDER BY hiredate
ENAME | HIREDATE |
---|---|
鈴木絢音 | 13-03-28 |
梅澤美波 | 16-09-04 |
賀喜遥香 | 18-12-03 |
井上和 | 22-02-01 |
SELECT ename, hiredate FROM emp ORDER BY hiredate ASC
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_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つの表があったとする。
empno | empname | deptno |
---|---|---|
1 | 堀内まり菜 | 1 |
2 | 飯田來麗 | 2 |
3 | 杉崎寧々 | (NULL) |
4 | 佐藤日向 | 1 |
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通りある。
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つの表があったとする。
empno | empname | deptno |
---|---|---|
1 | 堀内まり菜 | 1 |
2 | 飯田來麗 | 2 |
3 | 杉崎寧々 | (NULL) |
4 | 佐藤日向 | 1 |
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';
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を使うことにより、複数の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句を指定できなくなる。
たいていの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 empno, salary, (SELECT AVG(salary) FROM emp) AS avg_salary FROM emp
SELECT及びINSERT、UPDATE、DELETEのWHERE句にサブクエリを指定することができる。
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
)