SQLite | ゼロからはじめるSQL、30日で習得するSQLite:データ操作・設計 - Day18 制約

SQL SQLite
スポンサーリンク

Day18 前半

「そもそも“おかしなデータ”が入らないようにする」ための仕組みが制約

ここまで、
SELECT(読む)
UPDATE(書き換える)
DELETE(消す)
をやってきました。

ここで一度、視点をガラッと変えます。

「変なデータが入ってしまったから、UPDATE や DELETE で直す」
ではなく、

「そもそも“変なデータ”が入らないように、テーブル側で守りを固める」

そのための仕組みが 制約(constraint) です。

Day18 前半では、その中でも超基本であり超重要な

PRIMARY KEY
NOT NULL

という二つを、じっくりかみ砕いていきます。


制約とは何か

「このテーブルには、こういうルールでしかデータを入れさせない」という約束

制約(constraint)を一言でいうと、

「このテーブルに入っていいデータのルール」

です。

たとえば、

id は必ず一意(かぶらない)でなければならない
name は必ず入っていなければならない(NULL 禁止)

といったルールを、
テーブル定義の段階で“データベースに約束させる” のが制約です。

これをやっておくと、

アプリのバグで同じ id を二重に INSERT しようとしてもエラーになる
name を入れ忘れて INSERT しようとしてもエラーになる

つまり、
「おかしなデータが入る前に、データベースが門前払いしてくれる」
という状態になります。


PRIMARY KEY とは何か

「このテーブルの中で、絶対にかぶらない“番号札”」

まずは PRIMARY KEY(主キー) から。

PRIMARY KEY は、そのテーブルの中で

絶対に重複しない
NULL にならない

という特別な列(または列の組み合わせ)です。

イメージとしては、
「そのテーブルの中で、その行を一意に特定するための番号札」
だと思ってください。

たとえば、users テーブルを考えます。

id | name       | email
---+------------+-------------------
 1 | 山田太郎   | taro@example.com
 2 | 佐藤花子   | hanako@example.com
 3 | 鈴木一郎   | ichiro@example.com

ここで、id を PRIMARY KEY にすると、

id は 1, 2, 3, … と、テーブル内で一意
同じ id の行を二つ入れることはできない
id を NULL にすることもできない

というルールが自動的にかかります。


PRIMARY KEY を付けたテーブル定義の例

「id INTEGER PRIMARY KEY」がよく見る形

SQLite でよく見る users テーブルの定義は、こんな感じです。

CREATE TABLE users (
  id    INTEGER PRIMARY KEY,
  name  TEXT,
  email TEXT
);
SQL

ここで、

id INTEGER PRIMARY KEY

と書いていることで、

id は整数で、PRIMARY KEY(=一意かつ NULL 禁止)

という意味になります。

この状態で、次のような INSERT は成功します。

INSERT INTO users (id, name, email)
VALUES (1, '山田太郎', 'taro@example.com');
SQL

しかし、同じ id をもう一度入れようとするとエラーになります。

INSERT INTO users (id, name, email)
VALUES (1, '別の人', 'other@example.com');
SQL

データベースが、

「id=1 はもういるから、これは受け付けない」

と守ってくれるわけです。


なぜ PRIMARY KEY がそんなに重要なのか

「一意に特定できないと、JOIN も更新も削除も危険になる」

PRIMARY KEY がないテーブルを想像してみます。

name       | email
-----------+-------------------
山田太郎   | taro@example.com
山田太郎   | taro2@example.com

ここで、「山田太郎を削除したい」と思ったとき、
どっちの行を消せばいいのか、SQL からは判断できません。

UPDATE も同じです。

「山田太郎のメールアドレスを変えたい」と言っても、
どの行を更新すべきかが曖昧です。

さらに、他のテーブルから参照するとき(JOIN するとき)も、

users のどの行を指しているのか
一意に決められない

という問題が起きます。

だからこそ、

「このテーブルの1行を指す“絶対にかぶらないキー”」

として PRIMARY KEY を必ず用意する、というのが
データベース設計の大前提になります。


NOT NULL とは何か

「この列は“空っぽ”を許さない」というルール

次に NOT NULL です。

NOT NULL は、その列に対して

「NULL(値なし)を入れてはいけない」

という制約をかけます。

たとえば、users テーブルで

name は必須
email は任意

というルールにしたいとします。

CREATE TABLE users (
  id    INTEGER PRIMARY KEY,
  name  TEXT NOT NULL,
  email TEXT
);
SQL

このように name TEXT NOT NULL と書くと、

name に NULL を入れようとした瞬間にエラー

になります。

INSERT INTO users (id, name, email)
VALUES (1, NULL, 'taro@example.com');
SQL

これはエラーです。

一方で、email は NOT NULL を付けていないので、
NULL でも構いません。

INSERT INTO users (id, name, email)
VALUES (2, '佐藤花子', NULL);
SQL

これは成功します。


PRIMARY KEY と NOT NULL の関係

「PRIMARY KEY には自動的に NOT NULL が含まれている」

ここで一つ整理しておきたいのは、

PRIMARY KEY に指定された列は、自動的に NOT NULL になる

ということです。

つまり、

id INTEGER PRIMARY KEY
SQL

と書いた時点で、

id は一意である
id は NULL になってはいけない

という二つのルールが同時にかかっています。

なので、PRIMARY KEY の列に対して
わざわざ NOT NULL を重ねて書く必要はありません。

逆に言うと、

NOT NULL は「NULL 禁止」だけ
PRIMARY KEY は「一意 + NULL 禁止」

という違いがあります。


NOT NULL がないと何が困るのか

「本当は必須なのに、抜けたまま動き続けてしまう」

NOT NULL を付けないと、その列には NULL が入ってしまいます。

たとえば、本当は name が必須なのに、
NOT NULL を付け忘れてテーブルを作ったとします。

CREATE TABLE users (
  id    INTEGER PRIMARY KEY,
  name  TEXT,
  email TEXT
);
SQL

この状態だと、

INSERT INTO users (id, name, email)
VALUES (1, NULL, 'taro@example.com');
SQL

が通ってしまいます。

アプリ側で「name は必須」と思い込んでいても、
バグや想定外の経路から NULL が入る可能性があります。

そして、後から

「名前が NULL のユーザーがいて、画面表示で落ちる」
「メール送信時に、名前を前提にしたテンプレートが壊れる」

といった問題が起きます。

NOT NULL を付けておけば、
「おかしなデータが入る前に、INSERT 時点でエラーになる」
ので、問題を早期に発見できます。


セキュリティの視点から見る PRIMARY KEY / NOT NULL

「データの“穴”や“ダブり”を防ぐことが、そのまま防御になる」

セキュリティというと、
パスワードや暗号化の話を思い浮かべがちですが、
「データがきちんと一意で、欠損がない」
というのも立派な防御です。

PRIMARY KEY がない、あるいは守られていないと、

同じユーザーが二重に登録される
どの行が本物か分からなくなる
不正なレコードを紛れ込ませやすくなる

といった問題が起きます。

NOT NULL がないと、

本来必須の情報が抜けたまま処理が進む
監査ログに必要な情報が NULL で記録される
「誰が何をしたか」が追えなくなる

といったリスクが出てきます。

Day18 前半の段階では、

PRIMARY KEY は「一意で NULL 禁止の番号札」
NOT NULL は「この列は絶対に空っぽ禁止」

という二つの感覚だけ、しっかり持っておいてくれれば十分です。


小さな練習イメージ

頭の中で、次のようなテーブル定義を考えてみてください。

ユーザーを管理する users テーブルで、id は一意で必須、name も必須、email は任意。
ログイン履歴 login_logs で、id は一意、user_id は必須、created_at も必須。

どちらも、

id INTEGER PRIMARY KEY
必須の列には NOT NULL

という型に当てはめれば書けるはずです。


Day18 前半のまとめ

制約(constraint)は、「このテーブルに入っていいデータのルール」をデータベース側に持たせる仕組み。
PRIMARY KEY は「テーブル内で一意かつ NULL 禁止の“番号札”」で、行を一意に特定するための土台になる。
NOT NULL は「この列には NULL を入れてはいけない」というルールで、本来必須の情報が抜けるのを防ぐ。
PRIMARY KEY には自動的に NOT NULL が含まれており、「一意 + NULL 禁止」のセットになっている。
これらをきちんと付けておくことで、「おかしなデータ」が入る前にエラーで止まり、結果的にセキュリティや信頼性の向上につながる。

後半では、
PRIMARY KEY の自動採番(AUTOINCREMENT 的な使い方)の話、
複合 PRIMARY KEY(2列以上で一意にする)
NOT NULL と DEFAULT の組み合わせ
「制約エラーが出たときにどう読むか」
などを扱って、制約を“実務で使えるレベル”まで引き上げていきます。

タイトルとURLをコピーしました