トップ > SQL入門 > 29章
29章 制約(前半)
今回は制約について学んでいきましょう。

制約とは挿入するレコードの値を制限する機能です。

テーブルに挿入するデータが同じ値はエラーにしたいや、
NULL値はエラーにしたいという場合に便利な機能です。

この制約はSQLを初めて学ぶ人にとってイメージが難しい部分でもあります。

例えば、電話番号を挿入する列があって、挿入する値が同じ番号になってしまっては困りますね。

制約を使用すると、一意な値だけを挿入できるようにすることが簡単にできます。
またNULL値を挿入させたくないという場合もあります。

制約は以下の2通りで定義することが可能です。

・表の作成時
・表作成後

表作成時に定義する方法は以下の構文となります。
こちらも2つの方法があります。

・列レベル定義
・表レベル定義

[構文] 列レベル制約定義
 CREATE TABLE 表名
 ( 列A データ型 ,
  列B データ型 [ CONSTRAINT 制約名 ] 制約タイプ,
  列C データ型);

まずは列レベル定義の方法です。
制約を定義したい列の後にCONSTRAINTと定義していく方法です。
上記の例では列Bに対して制約を定義しています。

[構文] 表レベル制約定義
 CREATE TABLE 表名
 ( 列A データ型 ,
  列B データ型 ,
  列C データ型 ,
  [ CONSTRAINT 制約名 ] 制約タイプ(列B) );

一方、表レベルの定義方法は、制約を最後に指定する方法です。
表レベルの場合、列の定義がすべて終わってから、CONSTRAINTと指定する方法です。

表レベルの場合は定義する列名が必要になります。
上記の例では、列Bに対し制約を定義しています。

まずCONSTRAINT 制約名は[]で囲っていますが、これは省略可能という意味です。
CONSTRAINT 制約名は省略することができますが、その場合自動的に制約名が定義されます。

自動で定義される制約名はSYS_XXXXX(XXXXは数字)となります。
この制約名だとすぐに名前から、何の制約なのかが判断できない為、

制約名は自分で分かりやすい名前で定義することをお勧めします。
例えば表名_列名_制約タイプなんて制約名は分かりやすいですね。

そして構文に記載されている制約タイプは、使用する制約を指定します。

制約タイプ
・NOT NULL
・UNIQUE(一意制約)
・PRIMARY KEY(主キー)
・FOREIGN KEY(外部キー)
・CHECK

NOT NULL制約


まずはNOT NULL制約は、NULL値を挿入できないようにする制約です。

例えば、名前などの列は必須項目としてNULL値を
許可しないようにしたいという場合はNOT NULL制約を使用します。

NOT NULL制約は列レベルのみ定義できます。

UNIQUE制約


UNIQUE制約は一意制約とも呼ばれており、一意な値しか挿入できないようにする制約です。
ただし、NULL値は挿入可能です。
UNIQUE制約は列レベル、表レベル両方で定義することができます。

PRIMARY KEY制約


PRIMARY KEY制約は主キー制約とも呼ばれており、
NOT NULL制約とUNIQUE制約と同じ制約です。
同じ値またはNULL値は挿入できません。

PRIMARY KEY制約は列レベル、表レベル両方で定義することができます。

FOREIGN KEY制約


FOREIGN KEY制約は外部キー制約とも呼ばれており、
参照する列の値のみ挿入ができる制約となります。
詳しくは後ほどご紹介いたします。
FOREIGN KEY制約は列レベル、表レベル両方で定義することができます。

CHECK制約


CHECK制約はもっとも柔軟な制約となり、自分で条件を定義することができます。
FOREIGN KEY制約は列レベル、表レベル両方で定義することができます。

では実行例を見ていきましょう。

  SQL> CREATE TABLE emp1
    2  ( id number(5) constraint emp1_id_pk primary key,
    3    name varchar2(30) not null,
    4    mail varchar2(30) unique,
    5    tel  varchar2(10));

  Table created.


上記の例では、id列に主キー制約を定義し、制約名をemp1_id_pkとしています。
name列はNOT NULL制約、mail列は一意制約を定義しています。

NOT NULL制約、UNIQUE制約に関しては制約名を定義していないので、
自動的にSYS_XXXXという名前で作成されます。

ではINSERT文を実行していきましょう。

  SQL> INSERT INTO emp1 (id,name,mail,tel)
    2  VALUES (1,'TARO','TEST','090');

  1 row created.

  SQL> INSERT INTO emp1 (id,name,mail,tel)
    2  VALUES (NULL,'JIRO','TEST2','090');
    
    values (NULL,'JIRO','TEST2','090')
       *
    ERROR at line 2:
    ORA-01400: cannot insert NULL into ("ORA"."EMP1"."ID")


2回目のINSERT文がエラーとなりました。id列にNULL値を挿入しようとしいますが、
id列には主キー制約が定義されているので、NULL値は挿入できない為、エラーとなります。

  SQL> INSERT INTO emp1 (id,name,mail,tel)
    2  VALUES (1,'TARO','TEST','090');
    
  insert into emp1 (id,name,mail,tel)
  *
  ERROR at line 1:
  ORA-00001: unique constraint (ORA.EMP1_ID_PK) violated


次はid列に1という値を挿入していますが、主キーが定義されているので、
重複した値を挿入するとエラーとなります。
またmail列もTESTと同じ値なので、これもエラーとなります。

では次に表レベル定義の例を確認していきましょう。

  SQL> CREATE TABLE emp2
    2  ( id number(5),
    3    name varchar2(30) not null,
    4    mail varchar2(30),
    5    tel  varchar2(10),
    6    CONSTRAINT emp2_id_pk primary key(id),
    7    CONSTRAINT emp2_mail_uq unique(name));

  Table created.


表レベルの場合は、すべての列を定義した後で、制約を定義します。

今回は主キー制約をemp2_id_pkという名前でid列に定義し、
name列に一意制約をemp2_mail_uqという名前で定義しています。

NOT NULL制約は列レベルでしか定義できませんのでご注意ください。

今回は列レベル、表レベルで定義しているCREATE TABLE文を確認しましたが、
2つの例で作成したテーブル定義は同じです。列レベル、表レベルとは書き方の違いです。

いかがでしたでしょうか。列レベル、表レベルの定義方法をご紹介しましたが、
書き方が異なるだけで制約のレベルが変わるということではありません。

列、表レベルという言葉が紛らわしいですが、あくまでも列レベル、表レベルという
書き方の2種類があるとご理解いただければと思います。