新しいデータをテーブルに挿入するときによくあるエラーを見ていこう。
エラー1: 必須フィールドにNULLを入れようとした
PostgreSQLはデータベースのルールをちゃんと守るようにしてるんだ。エラーの原因になる制約の例を見てみよう:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL, -- 名前はNULLにできない
age INT
);
-- エラー: nameフィールドは必須だよ
INSERT INTO students (name, age) VALUES (NULL, 20);
結果: エラー null value in column "name" of relation "students" violates not-null constraint`。
どんなデータを追加してるかちゃんと気をつけてね。このカラムは前はNULLを許してたかもしれないけど、今は必須項目だよ。
エラー2: ユニークなカラムでデータが重複した
CREATE TABLE courses (
course_id SERIAL PRIMARY KEY,
course_name TEXT UNIQUE -- コース名はユニークじゃなきゃダメ
);
-- 最初の挿入はOK
INSERT INTO courses (course_name) VALUES ('SQL Basics');
-- 2回目の挿入でエラー
INSERT INTO courses (course_name) VALUES ('SQL Basics');
結果: エラー duplicate key value violates unique constraint`。
たいていこれは自分のミスじゃなくて、ユーザーがうっかり同じ操作をもう一度やっちゃっただけ。こういうときは特に何もしなくて大丈夫。
エラー3: 外部キー制約違反
CREATE TABLE enrollments (
enrollment_id SERIAL PRIMARY KEY,
student_id INT REFERENCES students(id), -- このIDの学生が存在しなきゃダメ
course_id INT REFERENCES courses(course_id)
);
-- エラー: ID=99の学生はいない
INSERT INTO enrollments (student_id, course_id) VALUES (99, 1);
結果: エラー insert or update on table "enrollments" violates foreign key constraint`。
こういうエラーが出るのはむしろ良いこと。データベースの整合性が壊れるよりマシだよ。たぶんDBを操作するコードにバグがあるか、データが古くなってる。どっちにしても、DBが整合性を守ってくれるのはありがたい。
PostgreSQLでのエラー処理
うん、エラーは起きるもの。でも大事なのは、気づくだけじゃなくてちゃんと対処できることだよ。
トランザクションでデータを守る
データを扱うときは、よくトランザクションを使ってデータの一貫性を保つよ。エラーが起きたら変更を元に戻せる。
例:2つのテーブルにデータを追加する場合。
BEGIN; -- トランザクション開始
-- studentsテーブルにデータを挿入
INSERT INTO students (name, age) VALUES ('Otto Lin', 21);
-- enrollmentsテーブルにレコードを挿入
-- ここでID=10のコースがなければエラーになる
INSERT INTO enrollments (student_id, course_id) VALUES (1, 10);
-- 全部うまくいったら
COMMIT;
-- エラーがあったら変更を元に戻す
ROLLBACK;
もしcourse_id = 10のコースがなかったら、studentsテーブルへの挿入もキャンセルされるよ。
トランザクション内でのエラー処理
PostgreSQLでは、エラーを予測してEXCEPTIONブロックを使ってクエリ内で処理できるんだ。
例:学生を追加してコースに登録する。エラーが起きたらログに記録する。
DO $$
BEGIN
-- データ挿入を試す
INSERT INTO students (name, age) VALUES ('Anna Song', 22);
INSERT INTO enrollments (student_id, course_id) VALUES (2, 999); -- エラー
-- 全部うまくいったら
RAISE NOTICE 'レコードが正常に追加されたよ!';
EXCEPTION
WHEN foreign_key_violation THEN
-- 外部キー違反を処理
RAISE WARNING '指定されたcourse_idのコースは存在しないよ。';
END $$;
ON CONFLICTでユニーク制約違反を防ぐ
UNIQUE制約違反のエラーは、ON CONFLICT構文で事前に防げるよ。どうするか指定できるんだ。
例:重複するコースを挿入しようとしたらスキップする。
INSERT INTO courses (course_name)
VALUES ('SQL Basics')
ON CONFLICT (course_name) DO NOTHING; -- 重複データはスキップ
または既存の行を更新する:
INSERT INTO courses (course_name)
VALUES ('SQL Basics')
ON CONFLICT (course_name) DO UPDATE
SET course_name = EXCLUDED.course_name || ' (Updated)';
ON CONFLICTオペレーターについては、次のレベルで大量データのロードをやるときにもっと詳しく話すね :P
データ操作でよくあるエラーとその防止法
もう見た通り、主なエラーの原因は:
- 制約違反(
NOT NULL、UNIQUE、FOREIGN KEY)。 - データ更新や削除時にクエリに
WHERE条件がない。 - トランザクションの実行順序ミス。
自分を守るために:
- 大きな操作にはトランザクションと
ROLLBACKを使おう。 - 挿入前にデータを必ずチェックしよう。
- エラーはログに残して分析しよう。
- 重複レコードを避けるために
ON CONFLICTを使おう。
これでエラーと戦う知識はバッチリ!覚えておいて:いいエンジニアはミスしない人じゃなくて、ミスをちゃんと直せる人だよ。
GO TO FULL VERSION