SQL入門 Oracle9i入門SQL編差分資料

試験範囲として追加された内容

2002年2月より、Oracle9iの内容が含まれた「SQL入門」が始まった。まずは以前の試験との変更点を紹介する。

結合の種類

 Oracle8i以前はOracle独自の結合構文のみだったが、Oracle9iではSQL:1999準拠の結合構文が使用できるようになった。

Oracle独自の結合(教科書) SQL:1999準拠の結合
直積演算
単純結合
 ・等価結合
 ・非等価結合
外部結合
内部結合(自己結合、同一表結合)
クロス結合
内部結合
 ・自然結合
 ・USING句を使用した結合
 ・ON句を使用した結合(等価条件、非等価条件)
外部結合
 ・右側外部結合
 ・左側外部結合
 ・完全外部結合

Oracle9i入門SQL編では、Oracle独自のSQLに加え、SQL:1999準拠の結合構文も試験範囲に加わった。

9i新機能ではないが、試験の範囲に加わったもの

Oracle9iの新機能というわけではないが、Oracle9i入門SQL編で追加になった試験範囲は次のとおり。

  1. INSERT文内での副問い合わせの使用
  2. DML文でのWITH CHECK OPTIONキーワードの使用
  3. MERGE文
  4. 関数・条件式など
    • NVL2
    • NULLIF
    • COALESCE
    • 条件式−CASE文
  5. 明示的デフォルト機能(明示的デフォルト値の使用)

名称(呼び方)が変わったもの

従来からの機能だが、8i以前と9i以降で呼び方が変わったものを紹介する。

8i以前9i以降
比較演算子比較条件
BETWEEN演算子BETWEEN条件

機能は使えるが、試験範囲からは外れたもの

1 SQLの種類

 Oracle9iでのSQLの種類は次のとおり。

1.データ検索
SELECT
2.データ操作文(DML)
INSERT, UPDATE, DELETE, MERGE
3.データ(トランザクション)制御文(DCL)
COMMIT, ROLLBACK, SAVEPOINT
4.データ定義文(DDL)
CREATE, ALTER, DROP, TRUNCATE, RENAME, GRANT, REVOKE

2 MERGE文(データの挿入または更新)

MERGE文は、Oracle9iから追加されたOracle独自のSQL文で、条件付きで表に行を追加したり、表の中の行を変更できる

【構文】

MERGE INTO 表名
 USING 元表名 ON (条件)
 WHEN MATCHED THEN
  UPDATE SET 表名.列名 = 元表名.列名
 WHEN NOT MATCHED THEN
  INSERT VALUES (元表名.列名);

【機能】

表と元表を比較し、条件と一致すれば更新(UPDATE)を行い、一致しなければ追加(INSERT)を行う。

【使用例】

本社従業員表と名古屋従業員表を照合し、一致する(本社従業員表に存在する)行は「名古屋従業員表のデータ」で「本社従業員表のデータ」を更新し、一致しない(本社従業員表に存在しない)行は、その行を本社従業員表に追加する。

○本社従業員表

従業員番号従業員名職種
7782高橋課長
7839社長
7934田村秘書

○名古屋従業員表

従業員番号従業員名職種
7566松岡部長
7698藤原部長
7782高橋部長

[SQL文]

MERGE INTO 本社従業員 h
 USING 名古屋従業員 n
 ON (h.従業員番号 = n.従業員番号)
WHEN MATCHED THEN
 UPDATE SET h.従業員名 = n.従業員名, h.職種 = n.職種
WHEN NOT MATCHED THEN
 INSERT VALUES (n.従業員番号, n.従業員名, n.職種);

[実行結果]

従業員番号従業員名職種(変更内容)
7782高橋課長(更新)
7839社長
7934田村秘書
7566松岡部長(追加)
7698藤原部長(追加)

3 明示的デフォルト機能

 例えばINSERT文で列名を指定してデータを追加するとき、指定しなかった列の値は、デフォルト値が設定されている列ならデフォルト値が、設定されていなければNULL値が格納される。

  1. 表の列(受注日)にDEFAULT値が設定されていないとき
    INSERT INTO 受注表 (商品番号, 顧客番号, 数量, 受注日)
     VALUES (9876, 'A-12345', 25, SYSDATE);
  2. 表の列(受注日)にDEFAULT値(SYSDATE)が設定されているとき
    INSERT INTO 受注表 (商品番号, 顧客番号, 数量)
     VALUES (9876, 'A-12345', 25);

Oracle9iでは、2のケースでDEFAULTキーワードを使用してを指定して、次のように記述できる。

INSERT INTO 受注表 (商品番号, 顧客番号, 数量, 受注日)
 VALUES (9876, 'A-12345', 25, DEFAULT);

このように、DEFAULTキーワードを使用して値を設定することを「明示的デフォルト値を使用する」という。
UPDATE文では次のように指定できる。

UPDATE 受注表
 SET 受注日 = DEFAULT
 WHERE 〜;

デフォルトキーワードを指定した場合、その列にデフォルト値が設定されていればデフォルト値が、設定されていなければNULL値が格納される。

4 SQL:1999構文を使用した直積演算(クロス結合)

Oracleでは、2つ以上の表を結合条件を指定せずに結合することを直積演算と呼ぶ。

Oracleでの直積演算の例

SELECT ename, dname
 FROM emp, dept;

emp表とdept表の全てのデータの組み合わせが表示される。

では、SQL:1999構文ではどのように記述するのだろうか。

SQL:1999構文での直積演算の構文

SELECT 表名1.列名, 表名2.列名
 FROM 表名1 CROSS JOIN 表名2

直積演算する表をCROSS JOIN句で連結する。SQL:1999ではクロス結合と呼ぶ。

SQL:1999でのクロス結合の例

SELECT ename, dname
 FROM emp CROSS JOIN dept;

5 SQL:1999構文を使用した単純結合(内部結合)

Oracleでの単純結合は、等価結合と非等価結合に分かれるが、SQL:1999では特に区別していない。しかし、Oracle独自のSQLでの結合条件は「列名 = 列名」という書き方しかなかったが、SQL:1999構文ではいろいろな書き方がある。

等価結合の構文1:NATURAL JOIN

[構文]

SELECT 表名1.列名, 表名2.列名
 FROM 表名1 NATURAL JOIN 表名2

[機能]

  1. 2つの表の同じ列名に基づいて等価結合する(列名は記述しない)
  2. 同じ列名であるが、データ型が異なる場合はエラーになる

[例]

Oracle独自のSQLの場合
SELECT ename, emp.deptno, dname
 FROM emp, dept
 WHERE emp.deptno = dept.deptno;
SQL:1999の場合
SELECT ename, deptno, dname
 FROM emp NATURAL JOIN dept;

等価結合の構文2:USING句を使用した結合

[構文]

SELECT 表名1.列名, 表名2.列名
 FROM 表名1 JOIN 表名2 USING (列名)

[機能]

  1. 2つの表の指定した列名に基づいて等価結合する
  2. 同じ列名であるが、データ型が異なる場合はエラーになる
  3. USING句で参照する列には、SQL文のどの箇所にも表名や別名などの修飾子を使用することはできない

[例]

Oracle独自のSQLの場合
SELECT ename, emp.deptno, dname
 FROM emp, dept
 WHERE emp.deptno = dept.deptno;
SQL:1999の場合
SELECT ename, deptno, dname
 FROM emp JOIN dept USING (deptno);

等価結合の構文3:ON句を使用した結合

[構文]

SELECT 表名1.列名, 表名2.列名
 FROM 表名1 JOIN 表名2 ON 表名1.列名 = 表名2.列名

[機能]

  1. ON句の条件に基づいて結合する

[例]

Oracle独自のSQLの場合
SELECT ename, emp.deptno, dname
 FROM emp, dept
 WHERE emp.deptno = dept.deptno;
SQL:1999の場合
SELECT ename, emp.deptno, dname
 FROM emp JOIN dept ON emp.deptno = dept.deptno;

[特徴]

  1. 結合する列を指定したいときや、任意の条件を指定したいときに利用する
  2. 結合条件が他の検索条件(WHERE句)から分離され、コードが分かりやすくなる

等価結合の確認問題

以下の3つの表がある。

[DETP表]

DEPT_IDDEPT_NAMECITY_ID
10営業J001
20教育E001
30開発A002

[CITY表]

CITY_IDCITYCOUNTRY_ID
A002ワシントン900
E001ロンドン500
J001東京300

[COUNTRY表]

COUNTRY_IDCOUNTRY
300日本
500イギリス
900アメリカ

この3つの表を結合して以下のような結果を得るためのSQL文をそれぞれの構文で作成せよ。

[結合結果]

DEPT_NAMECITYCOUNTRY
教育ロンドンイギリス
開発ワシントンアメリカ
営業東京日本

[SQL]

  1. Oracle結合
  2. SQL:1999構文のNATURAL JOIN
  3. SQL:1999構文のUSING
  4. SQL:1999構文のON

非等価結合の構文

2つ以上の表を結合するとき、結合条件に「=」を使用しない結合をOracleでは非等価結合と呼ぶ。

【成績表】

番号氏名得点
1AAAAA100
2BBBBB60
3CCCCC75
4DDDDD40
5EEEEE80

【評価表】

範囲1範囲2評価
10080A
7960B
590C

【非等価結合文】

SELECT t1.番号, t1.氏名, t1.得点, t2.評価
 FROM 成績表 t1, 評価表 t2
 WHERE t1.得点 BETWEEN t2.範囲1 AND t2.範囲2;

【実行結果】

番号氏名得点評価
1AAAAA100A
2BBBBB60B
3CCCCC75B
4DDDDD40C
5EEEEE80A

このように、2つの表を=ではない演算子で結合する結合文を非等価結合と呼ぶ。

なお、SQL:1999構文では次のように記述する。

【SQL:1999構文での非等価結合】

SELECT t1.番号, t1.氏名, t1.得点, t2.評価
 FROM 成績表 t1 JOIN 評価表 t2
 ON t1.得点 BETWEEN t2.範囲1 AND t2.範囲2;

6 SQL:1999構文を使用した外部結合(左側/右側/完全外部結合)

外部結合とは、内部結合の結果とともに、一致しない行も戻す結合のことである。
Oracle独自のSQLでは、外部結合は「列名 = 列名(+)」「(+)列名 = 列名」という書き方だったが、SQL:1999構文では次の3タイプがある。

LEFT OUTER JOIN
左側外部結合
RIGHT OUTER JOIN
右側外部結合
FULL OUTER JOIN
完全外部結合(OracleのSQL構文ではできない)

【SQL:1999での外部結合の構文】

SELECT 表名1.列名, 表名2.列名
FROM 表名1 LEFT | RIGHT | FULL OUTER JOIN 表名2 ON (表名1.列名 = 表名2.列名)
  1. ON句の条件に基づいて外部結合を行う
  2. LEFTは(+)を右側に、RIGHTは(+)を左側につけた場合と同じになる
  3. FULLは完全結合

以下、サンプル表を使って各構文を説明する。

【サンプル表】

○従業員表

NAMEADDRJOBDEPT_ID
SyomaShinagawaSal130
RyotaroYokoyamaEng110
TakumaTokushimaDoc120
MasatoShinagawaMgn130
AyanoTokushima

○部門表

DEPT_IDDEPT_NAMELOC
110KensetsuTokyo
120HokenOsaka
130KaikeiChiba
140KyoikuKobe

内部結合(復習)

【Oracle独自のSQL】

SELECT e.name, d.dept_name, d.dept_id
 FROM 従業員表 e, 部門表 d
 WHERE e.dept_id = d.dept_id;

【SQL:1999のON句を用いた内部結合】

SELECT e.name, d.dept_name, d.dept_id
 FROM 従業員表 e JOIN 部門表 d
 ON e.dept_id = d.dept_id;

【実行結果】

NAMEDEPT_NAMEDEPT_ID
RyotaroKensetsu110
TakumaHoken120
SyomaKaikei130
MasatoKaikei130

※2つの表を内部結合したとき、まだ部門に所属していない従業員「Ayano」は表示されない。また、従業員が所属していない部門140も表示されていない。

左側外部結合

従業員について、部門に所属していなくても全員表示する。

【Oracle独自のSQL】

SELECT e.name, d.dept_name, d.dept_id
 FROM 従業員表 e, 部門表 d
 WHERE e.dept_id = d.dept_id(+);

【SQL:1999の左側外部結合】

SELECT e.name, d.dept_name, d.dept_id
 FROM 従業員表 e LEFT OUTER JOIN 部門表 d
 ON e.dept_id = d.dept_id;

【実行結果】

NAMEDEPT_NAMEDEPT_ID
RyotaroKensetsu110
TakumaHoken120
SyomaKaikei130
MasatoKaikei130
Ayano

※JOINキーワードの左側(LEFT)にある表についてすべての行を取り出す。

右側外部結合

従業員が所属していなくても、部門についてはすべての行を表示する。

【Oracle独自のSQL】

SELECT e.name, d.dept_name, d.dept_id
 FROM 従業員表 e, 部門表 d
 WHERE e.dept_id(+) = d.dept_id;

【SQL:1999の右側外部結合】

SELECT e.name, d.dept_name, d.dept_id
 FROM 従業員表 e RIGHT OUTER JOIN 部門表 d
 ON e.dept_id = d.dept_id;

【実行結果】

NAMEDEPT_NAMEDEPT_ID
RyotaroKensetsu110
TakumaHoken120
SyomaKaikei130
MasatoKaikei130

Kyoiku140

※JOINキーワードの右側(RIGHT)にある表についてすべての行を取り出す。

完全外部結合

部門に所属していなくても、全従業員の行を表示したい。また、従業員が所属していなくても、全部門の行を表示する。

【Oracle独自のSQL】

Oracleには、完全外部結合を行う構文は存在しない。しかし、UNION句を用いて同様の結果を表示させることはできる。

SELECT e.name, d.dept_name, d.dept_id
 FROM 従業員表 e, 部門表 d
 WHERE e.dept_id(+) = d.dept_id
UNION
SELECT e.name, d.dept_name, d.dept_id
 FROM 従業員表 e, 部門表 d
 WHERE e.dept_id = d.dept_id(+);

【SQL:1999の完全外部結合】

SELECT e.name, d.dept_name, d.dept_id
 FROM 従業員表 e FULL OUTER JOIN 部門表 d
 ON e.dept_id = d.dept_id;

【実行結果】

NAMEDEPT_NAMEDEPT_ID
RyotaroKensetsu110
TakumaHoken120
SyomaKaikei130
MasatoKaikei130
Ayano


Kyoiku140

※JOINキーワードの右側(RIGHT)にある表についてすべての行を取り出す。

7 新しい関数・条件式

それぞれを順番に紹介する。

7-1 NVL2関数

列の値がNULLであった場合、別の値に置き換えるNVL関数は教科書で紹介した。

【NVL関数の構文(復習)】

NVL(列名, 値)

【NVL関数の機能(復習)】

1つ目の引数に指定された列の値を調べ、NULLであれば2つ目の引数の値を、NULLでなければ列の値を返す。

【NVL関数の使用例(復習)】

SELECT comm, NVL(comm, 0) FROM emp;

commNVL(comm, 0)
300300

0

これに対し、NVL2関数はNVL関数を拡張したOracle独自の関数で、NULLでない場合の値を指定することができる。

【NVL2関数の構文】

NVL2(式1, 値1, 値2)

式1:NULLを含む可能性がある列または式
   (任意のデータ型を指定可能)
値1:式1がNULLでない場合に戻す値
値2:式1がNULLである場合に戻す値
   (LONG型以外の任意のデータ型を指定可能)

【NVL2関数の機能】

1つ目の引数に指定された列の値を調べ、NULLでなければ2つ目の引数の値を、NULLであれば列の値を返す。

【NVL2関数の使用例】

SELECT comm, NVL2(comm, 'データあり', 'データなし') FROM emp;

commNVL2(comm, 'データあり', 'データなし')
300データあり

データなし

7-2 NULLIF関数

【NULLIF関数の構文】

NULLIF(式1, 式2)

【NULLIF関数の機能】

1つ目の式と2つ目の式を調べ、式1=式2であればNULLを、式1≠式2であれば式1を返す。
ただし、式1にNULLを含めてはならない(全ての結果がNULLになる)。

【NULLIF関数の使用例】

SELECT comm, NVL(comm, 0), NULLIF(NVL(comm, 0), comm)
FROM emp;

commNVL(comm, 0)NULLIF(NVL(comm, 0), comm)
300300

00

7-3 COALESCE関数

【COALESCE関数の構文】

COALESCE(式1, 式2, ・・・, 式n)

【COALESCE関数の機能】

引数に指定された式を先頭から調べ、最初にNULLでない式を返す。

【COALESCE関数の使用例】

SELECT comm, mgr, coalesce(comm, mgr, 999)
 FROM emp;

commmgrcoalesce(comm, mgr, 999)

79027902
3007698300


999

7-4 CASE式

CASE式またはDECORD式を利用して、SQL文の中でif-then-elseロジックを使うことができる。case式はSQL:1999構文に準拠した条件文である。

【CASE式の構文】

CASE 式 WHEN 条件1 THEN 値1
    [ WHEN 条件2 THEN 値2
     ・
     ・
     ELSE デフォルト値 ] END

【CASE式の機能】

式の値が条件1と一致した場合、値1を返す。条件1と一致しなかった場合、次の条件と比較し、一致した条件の値を返す。
いずれの条件にも一致しなかった場合、デフォルト値を返す。ELSE句を省略した場合はNULLを返す。

【CASE式の使用例】

SELECT
 job,
 CASE job
  WHEN 'SALESMAN' THEN '営業'
  WHEN 'PRESIDENT' THEN '社長'
  ELSE 'その他'
 END "職種"
FROM emp;

job職種
SALESMAN営業
CLEAKその他
PRESIDENT社長
MANAGERその他

7-5 DECODE式

DECODE式は、CASE式のOracle版である。

【DECODE式の構文】

DECODE(式, 条件1, 値1, 条件2, 値2, ・・・, デフォルト値)

【DECODE式の機能】

式の値が条件1と一致した場合、値1を返す。条件1と一致しなかった場合、次の条件と比較し、一致した条件の値を返す。
いずれの条件にも一致しなかった場合、デフォルト値を返す。デフォルト値を省略した場合はNULLを返す。

【DECODE式の使用例】

SELECT
 job,
 DECODE(job,
  'SALESMAN', '営業',
  'PRESIDENT', '社長',
  'その他'
 ) "職種"
FROM emp;

job職種
SALESMAN営業
CLEAKその他
PRESIDENT社長
MANAGERその他

7-6 その他教科書には載っていないが試験範囲である関数

【数値関数】

関数名機能
CELI(n)n以上の最も小さい整数を返すCEIL(3.14)は4
FLOOR(n)n以下の最も大きい整数を返すFROOR(3.14)は3

【文字関数】

関数名機能
RPAD(char1, n, char2)n桁になるようにchar1の右にchar2を埋める
(LPADの逆)
TRIM([LEADING | TRAILING | BOTH] [char1 FROM] char2)char2の先頭、最後または両方からchar1を切り捨てる
(余分な空白を取るなどに利用)
REPLACE(char1, char2[, char3])char1の中からchar2を探し、char3に置き換える

8 WITH CHECK OPTIONキーワード

例えばINSERT文で副問い合わせを使用する。

INSERT INTO (SELECT empno, ename, deptno
        FROM emp
        WHERE deptno = 10)
 VALUES (9999, 'ANDO', 20);

この例では、副問い合わせで「deptno = 10」としているが、VALUES句に指定したデータはdeptnoが20である。しかし、副問い合わせのWHERE条件に関係なくデータを追加できる(当たり前だが・・・)。

これを、副問い合わせのWHERE条件に一致しないデータは追加できないように制限をかけることができる。

INSERT INTO (SELECT empno, ename, deptno
        FROM emp
        WHERE deptno = 10
        WITH CHECK OPTION)
 VALUES (9999, 'ANDO', 20);

このように、副問い合わせにWITH CHECK OPTIONキーワードをつけることにより、追加できるデータを制限できる。この例では、次のエラーがでる。

2行でエラーが発生しました。
ORA-01402: ビューのWITH CHECK OPTION WHERE句でエラーが発生しました。

補足

本来、WITH CHECK OPTION WHERE句はビュー(VIEW)を作成するときに指定するキーワードで、これを指定すると、ビューを通したDML文でデータチェックができるようになる。ビューの作成はOracle入門の範囲だが、DML文での副問い合わせでも同じことができるので、試験範囲として加わった。

8 その他の教科書補足

8-1 PL/SQLとは(追加説明)

 PL/SQL(Procedural Language/SQL)は、リレーショナルデータベースの標準言語であるSQLに手続き機能を拡張した、オラクル社独自の言語である。OracleServerおよびOracleツール(SQL*Plusなど)で使用できる。
 データ検索文、データ操作文(DML)をプロシージャ単位に組み込んで使用するため、「トランザクション処理言語」と呼ばれることもある。

8-2 login.sqlファイル

 SQL*Plusではページの縦横の幅などを自由に変更できる。しかし、SQL*Plusを起動するたびにそれらの設定を毎回行うのは面倒である。
 SQL*Plusは、起動時にlogin.sqlファイルを読み込み、そのファイルに従った設定を行う。つまり、login.sqlファイルを編集し、自分の好きな環境でSQL*Plusを起動できる。

8-3 暗黙のロールバック

 エラーが発生したSQL文は直ちにロールバックされ、変更対象の行に影響は無い(トランザクションではないことに注意)。また、停電やOSのフリーズなどの障害が発生した場合、サーバ再起動後、Oracleは自動的に回復処理を行い、確定していないトランザクションをロールバックする。これらの自動的に行われるロールバックを「暗黙のロールバック」と呼ぶ。


[ TOP ]