設計をする上で
役立った制約について
2017-04-08 (土) 第20回中国地方DB勉強会
高橋 一騎
自己紹介
名前: 高橋 一騎(たかはし いっき)
年齢: 26歳 (いわゆる平成生まれ)
Twitter: @ikkitang (https://twitter.com/ikkitang)
Github: TakahashiIkki (https://github.com/TakahashiIkki)
所属: 日本PostgreSQLユーザー会 (なお、PostgreSQLの経験は..)
岡山モバイルアプリ開発勉強会
2
もくじ
1. RDBにおける制約の定義とは
2. 制約の種類の紹介
3. 制約を使う事のメリット について
3
1.RDBにおける制約の定義とは
4
(一般的な)制約とは・・
1. 制限や条件をつけて、自由に活動させないこと
2. 物事の成立に必要な条件や規定
5
(一般的な)制約とは・・
1. 制限や条件をつけて、自由に活動させないこと
2. 物事の成立に必要な条件や規定
6
RDBにおける制約とは・・
1. データを成立させる為に守らないといけない規定。
2. 正しいデータがどうあるべきか表現する為の規定。
7
RDBにおける制約とは・・
1. データを成立させる為に守らないといけない規定。
2. 正しいデータがどうあるべきか表現する為の規定。
8
エンジニアが
RDBにおける制約とは・・
1. データを成立させる為に守らないといけない規定。
2. 正しいデータがどうあるべきか表現する為の規定。
9
設計者が
RDBにおける制約の対象
制約は
テーブル(Table) または 列(Column) 単位で付ける。
10
RDBにおける制約の対象
制約は
テーブル(Table) または 列(Column) 単位で付ける。
11
CREATE TABLE customers (
id integer
, name varchar(50) NOT NULL
, gender integer CHECK (gender IN (0, 1))
, PRIMARY KEY(id)
);
RDBにおける制約の対象
制約は
テーブル(Table) または 列(Column) 単位で付ける。
12
CREATE TABLE customers (
id integer
, name varchar(50) NOT NULL
, gender integer CHECK (gender IN (0, 1))
, PRIMARY KEY(id)
);
RDBにおける制約
制約に反したデータを登録しようとした時、
データはDBに登録されずにエラーになる。
13
RDBにおける制約
制約に反したデータを登録しようとした時、
データはDBに登録されずにエラーになる。
14
不正なデータの登録(バグ)から、
テーブルのデータをエラーという形で守る。
制約違反時のエラー例 (PostgreSQL 9.3.15)
customers
15
id
(PRIMARY)
name
(NOT NULL)
gender
(CHECK gender IN (0, 1))
1 高橋 POST 0
2 高橋 GRE 1
3 高橋 SQL 0
制約違反時のエラー例 (PostgreSQL 9.3.15)
customers
16
id
(PRIMARY)
name
(NOT NULL)
gender
(CHECK gender IN (0, 1))
1 高橋 POST 0
2 高橋 GRE 1
3 高橋 SQL 0
INSERT INTO customers (id, name, gender) VALUES (1, ‘高橋 MySQL’, 1);
制約違反時のエラー例 (PostgreSQL 9.3.15)
customers
17
id
(PRIMARY)
name
(NOT NULL)
gender
(CHECK gender IN (0, 1))
1 高橋 POST 0
2 高橋 GRE 1
3 高橋 SQL 0
INSERT INTO customers (id, name, gender) VALUES (1, ‘高橋 MySQL’, 1);
ERROR: duplicate key value violates unique constraint "customers_pkey"
DETAIL: Key (id)=(1) already exists.
制約違反時のエラー例 (PostgreSQL 9.3.15)
customers
18
id
(PRIMARY)
name
(NOT NULL)
gender
(CHECK gender IN (0, 1))
1 高橋 POST 0
2 高橋 GRE 1
3 高橋 SQL 0
insert into customers (id, name, gender) values (4, NULL, 0);
制約違反時のエラー例 (PostgreSQL 9.3.15)
customers
19
id
(PRIMARY)
name
(NOT NULL)
gender
(CHECK gender IN (0, 1))
1 高橋 POST 0
2 高橋 GRE 1
3 高橋 SQL 0
insert into customers (id, name, gender) values (4, NULL, 0);
ERROR: null value in column "name" violates not-null constraint
DETAIL: Failing row contains (4, null, 0).
第一章 まとめ
DB設計者は【制約】という形で
テーブルのデータがどうあるべきかを定義する。
RDBでは、制約に違反したデータを
登録しようとした時は、エラーとなるため、
制約を定義することで、データの整合性を保てる。
20
2.制約の種類の紹介
21
CHECK 制約
22
CHECK 制約
23
対象 列 もしくは テーブル に対して定義
書式
列制約: [column] [型] CHECK (条件)
テーブル制約: CHECK (条件)
例 gender integer CHECK (gender IN (0, 1))
内容 条件を満たすデータのみ指定列に登録出来るようにする。
サポート MySQL , PostgreSQL , SQLServer
CHECK 制約 の使い所 (1)
24
「ここの gender カラム、0: 男性 、1: 女性 で
良いですよね? 他の場合ありますか?」
=> gender カラム に CHECK制約 で
0 or 1 の 条件を付けて、他の場合を潰す。
CHECK 制約 の使い所 (1)
25
「ここの gender カラム、0: 男性 、1: 女性 で
良いですよね? 他の場合ありますか?」
=> gender カラム に CHECK制約 で
0 or 1 の 条件を付けて、他の場合を潰す。
※ CHECK 制約の注意事項 有!!
CHECK 制約 の使い所 (2)
26
CHECK 制約 の使い所 (2)
27
それぞれの教科分類について
決められた教科しか登録したくない。
CHECK 制約 の使い所 (2)
28
CHECK 制約 の使い所 (2)
29
CASE文 で 評価式を定義する事で
制御する事が出来る
CHECK 制約 の 注意事項
30
・ CHECK (評価式) で評価するが、
評価式にサブクエリを使う事は出来ない。
・ 評価式 が True もしくは Null の時、「条件を満たす」
=> NOT NULL 制約とセットで!
NOT NULL 制約
31
NOT NULL 制約
32
対象 列 に対して定義
書式 列制約: [column] [型] NOT NULL
例 name integer NOT NULL
内容 null の値を指定列に登録する事が出来ないようにする。
サポート MySQL , PostgreSQL , SQLServer
NOT NULL 制約 の使い所
33
「ここの name カラム、NULL 値入った時どうします?」
=> name カラム に NOT NULL 制約 を付けて
パターンを潰す。
UNIQUE 制約
34
UNIQUE 制約
35
対象 列 もしくは テーブル に対して定義
書式
列制約: [column] [型] UNIQUE
テーブル制約: UNIQUE (UNIQUEになる列)
例 id integer UNIQUE
内容
指定列に対して同じ値を持つ行が
1行より多い場合は登録出来ないようにする。
サポート MySQL , PostgreSQL , SQLServer
UNIQUE 制約 の使い所
36
「ここの my_numberのカラム、重複したらどうします?」
=> my_number カラム に UNIQUE 制約 を付けて
パターンを潰す。
UNIQUE 制約 の注意事項
37
・ NULL 値 は UNIQUE制約の対象とされない。
INSERT INTO customers (id, my_number)
VALUES (1, null) , (2, null);
が登録出来るので、注意。
PRIMARY KEY 制約
38
PRIMARY KEY 制約
39
対象 テーブル に対して定義
書式 テーブル制約: PRIMARY KEY (一意性を保証する列)
例 PRIMARY KEY (id)
内容
指定列または指定列のグループをテーブル内の一行を特定するための
値として使用出来る事を保証する。 (NOT NULL + UNIQUE 制約)
サポート MySQL , PostgreSQL , SQLServer
PRIMARY KEY 制約の使い所
40
「customersテーブルのデータ更新したいんだけど、
更新するレコードの特定はどうすればいいですか?」
=> テーブル内の行を特定する為のカラムに
PRIMARY KEY 制約を指定する。
PRIMARY KEY 制約の注意事項
41
・ PRIMARY KEY 制約は、各テーブルにつき、
一つのみ定義出来る。
※ UNIQUE 制約は 複数回定義出来る。
外部キー 制約
42
外部キー 制約
43
対象 列、テーブル に対して定義
書式
列制約: [column] [型] REFERENCES 参照テーブル(参照テーブルの列)
テーブル制約: FOREIGN KEY (対象列) REFERENCES 参照テーブル(参照テーブルの列)
例
subject_group_id REFERENCES subject_groups(id)
(もしくは、 FOREIGN KEY (subject_group_id) REFERENCES subjects_groups (id) )
内容
指定列または指定列のグループを他のテーブルの指定列 または
グループの値と一致しないと登録できないようにする制約。
サポート MySQL , PostgreSQL , SQLServer
外部キー 制約 の使い所
44
外部キー 制約 の使い所
45
subject_groups テーブルと
必ず関連付けられるようにしたい
外部キー 制約 の使い所
46
外部キー 制約 の使い所
47
subject_groups の id キー と
関連付ける。
外部キー 制約の注意事項
48
・ デフォルトでは、関連付けの為に参照されている
列を更新、削除 するとエラーとなる。
=> ON DELETE や ON UPDATE オプションで
動作を設定する。
外部キー 制約の注意事項
~ ON UPDATE, ON DELETE オプション ~
49
NO ACTION
被参照列の 更新 / 削除 を行った場合、エラーとする。
(Defaultはこれ)
RESTRICT
`NO ACTION` と 同じ動作をする。 MySQLとSQLServerでは同じ意味。
PostgreSQLでの大きな違いは遅延評価が出来ないこと。
トランザクション内で宣言を追加すると、Commit時に評価出来るようになる。
CASCADE
更新: 被参照列の更新に合わせて、参照列も更新する。
削除: 被参照列が削除されると、参照列も削除する。
SET NULL 被参照列が更新 / 削除された時、 参照列 を NULL にする。
SET DEFAULT 被参照列が更新 / 削除された時、 参照列を Default値にする。
排他 制約
50
排他 制約
51
・・・ 理解しきれませんでした(´・ω・`)
排他 制約
52
PostgreSQL マニュアル より
(https://www.postgresql.jp/document/9.1/html/ddl-constraints.html)
CREATE TABLE circles (
c circle,
EXCLUDE USING gist (c WITH &&)
);
排他 制約
53
PostgreSQL マニュアル より
(https://www.postgresql.jp/document/9.1/html/ddl-constraints.html)
CREATE TABLE circles (
c circle,
EXCLUDE USING gist (c WITH &&)
);
gist: インデックスの種類
排他 制約
54
PostgreSQL マニュアル より
(https://www.postgresql.jp/document/9.1/html/ddl-constraints.html)
CREATE TABLE circles (
c circle,
EXCLUDE USING gist (c WITH &&)
);
c: 指定列
排他 制約
55
PostgreSQL マニュアル より
(https://www.postgresql.jp/document/9.1/html/ddl-constraints.html)
CREATE TABLE circles (
c circle,
EXCLUDE USING gist (c WITH &&)
);
&&: 演算子
排他 制約
56
PostgreSQL マニュアル より
(https://www.postgresql.jp/document/9.1/html/ddl-constraints.html)
CREATE TABLE circles (
c circle,
EXCLUDE USING gist (c WITH &&)
);
c って カラムの全ての値に対して
&& って演算子で比較した時、
全て false か null が返らないといけない。
また、比較は高速化の為に
gist index で行う ・・的な意味?
排他 制約
57
gist index を 検索の為の高速なインデックスだとすると
CREATE TABLE customers (
id integer NOT NULL,
EXCLUDE USING gist (id WITH =)
);
id 列 に対して 演算子 `=` で比較した時、
どの値も false か null を返す
=> 擬似的に 一意制約 を 作る事が出来る。
(補足資料)排他 制約の使用用途
58
範囲型に対して、重なりが無い事を保証するのに
使ったりする。
例えば、
会議室の予約 という観点で見た時に、
9:00 〜 11:00 という予約が抑えられている状態で
10:30 〜 12:00 という予約を抑えようとすると、
エラーにする事が出来る。
第二章 まとめ
59
CHECK制約 評価式を満たさない値を登録する事を制限する。
NOT NULL制約 null 値を登録する事を制限する。
UNIQUE制約 重複したデータを登録する事を制限する。
PRIMARY KEY制約
NOT NULL + UNIQUE 制約
テーブルに最大で一つ設定する事が出来る。
外部キー制約 関連付けが出来ない行を登録する事を制限する。
排他制約
指定の演算子で比較した時、同値と満たす事が出来る値を
登録する事を制限する。
3.制約を使う事のメリットについて
60
制約を使うメリット
メリット
制約に違反したデータは保存されないので
テーブルのデータを守る事が出来る。
61
制約を使うメリット
メリット
臭いものに蓋が出来る。
62
制約を使うメリット
customers
63
id name
gender
1 高橋 POST 0
2 高橋 GRE 1
3 高橋 SQL 0
0・1 以外の時どうする?NULLの時どうする?
NULLの時どうする?
重複した時どうする?
レコード の一意性はどうやって保証する?
制約を使うメリット
64
制約を使うメリット
65
全カラムを指定して該当レコード指定
制約を使うメリット
66
制約を使うメリット
67
例外パターンを考慮したコーディング
制約を使うメリット
customers
68
id
(PRIMARY)
name
(NOT NULL)
gender
(CHECK gender IN (0, 1))
1 高橋 POST 0
2 高橋 GRE 1
3 高橋 SQL 0
NULLの時どうする?
重複した時どうする?
NULLの時どうする? 0・1 以外の時どうする?
レコード の一意性はどうやって保障する?
制約を使うメリット
customers
69
id
(PRIMARY)
name
(NOT NULL)
gender
(CHECK gender IN (0, 1))
1 高橋 POST 0
2 高橋 GRE 1
3 高橋 SQL 0
NULLの時どうする?
重複した時どうする?
NULLの時どうする?
レコード の一意性はどうやって保障する?
0・1 以外の時どうする?
制約を使うメリット
70
制約を使うメリット
71
クエリをシンプルに書くことが出来る。
制約を使うメリット
72
ロジックをシンプルに書くことが出来る。
制約を使うメリット
メリット
「運用回避」だったものを
破ったらエラー、の「制約」として定義出来る。
=> 「起こり得ない」から「起こらない」に。
73
制約を使うメリット
メリット
「運用回避」だったものを
破ったらエラー、の「制約」として定義出来る。
=> 「起こり得ない」から「起こらない」に。
74
結果としてロジックをシンプルに。
第三章 まとめ
制約を使うメリット
・ データを守る事が出来る。
・ 「起こり得ない」事象を 「起こらない」事象に
変える事が出来る。
75
告知
76
オープンセミナー2017 @ 岡山
77
オープンセミナー2017 @ 岡山
テーマ: 『レガシーと闘え』
日時: 2017年 5月 13日 (土) 10:00 ~ 17:40
場所: さん太ホール
参加受付中です! 詳しくは Web へ
-> http://okayama.open-seminar.org/
78
第十三回 岡山モバイルアプリ開発 もくもく会
79
第十三回 岡山モバイルアプリ開発 もくもく会
内容: ゆっるゆるのもくもく回
日時: 2017年 4月 22日 (土) 10:00 ~ 17:00
場所: ギークハウス岡山 甘酒処ギー岡カフェ
参加受付中です! 詳しくは Web へ
-> https://okmoku.connpass.com/event/53023/
80
ご清聴ありがとうございました
m(_ _)m
81

設計をする上で役にたった制約について