既にレコードが存在するテーブルに対して、NOT NULL 制約付きのフィールドを追加したいとします。しかし、既存のデータは追加するフィールドの値を持たないので、NOT NULL 制約を違反してしまいます。これらを共存させるには一手間必要なので、Prisma と SQLite を用いて方法を解説します。
大まかな手順は以下の通りです。
- 一時的に NULL 許容でフィールドを追加する。
- すべてのレコードに追加したフィールドの値をセットする。
- 追加したフィールドに NOT NULL 制約を追加する。
想定する環境
Prisma で定義されたスキーマがあり、DB である SQLite 上に members
テーブルが生成されているとします。既存のレコードを削除することなく、members
テーブルに TEXT 型の kana
フィールド (NOT NULL 制約付き) を追加するのが目標です。
/prisma/schema.prisma
model Member {
id Int @id @default(autoincrement())
name String
avatar String
@@map("members")
}
CREATE TABLE IF NOT EXISTS "members" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL,
"avatar" TEXT NOT NULL
);
sqlite> SELECT * FROM "members";
id|name|avatar
1|鈴木|https://picsum.photos/200/300.jpg?random=1
2|佐藤|https://picsum.photos/200/300.jpg?random=2
3|田中|https://picsum.photos/200/300.jpg?random=3
手順
SQLite の CLI でデータベースに接続します。テーブルを操作できれば、DB への接続手段は問いません。
sqlite3 prisma/dev.db
はじめにスキーマを変更して、NULL 許容で kana
フィールドを追加します。
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 078feff..24c96d7 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -8,8 +8,9 @@ datasource db {
}
model Member {
id Int @id @default(autoincrement())
name String
+ kana String?
avatar String
@@map("members")
続いて DB に変更を適用します。今回はデモのため Prisma CLI の push
コマンドを使用しますが、変更の履歴 (マイグレーションファイル) が必要な場合は migrate
コマンドに適宜切り替えてください。
npx prisma db push
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": SQLite database "dev.db" at "file:./dev.db"
🚀 Your database is now in sync with your Prisma schema. Done in 8ms
✔ Generated Prisma Client (v5.4.2) to ./node_modules/@prisma/client in 48ms
テーブルを確認すると kana
フィールドが追加されています。
sqlite> .schema members
id|name|avatar|kana
1|鈴木|https://picsum.photos/200/300.jpg?random=1|NULL
2|佐藤|https://picsum.photos/200/300.jpg?random=2|NULL
3|田中|https://picsum.photos/200/300.jpg?random=3|NULL
既存のレコードに対して、kana
フィールドの値を更新します。
set_kana.sql
UPDATE "members"
SET "kana" = CASE
WHEN "id" = "1" THEN "スズキ"
WHEN "id" = "2" THEN "サトウ"
WHEN "id" = "3" THEN "タナカ"
ELSE ""
END;
sqlite> .read set_kana.sql
sqlite> SELECT * FROM "members";
id|name|avatar|kana
1|鈴木|https://picsum.photos/200/300.jpg?random=1|スズキ
2|佐藤|https://picsum.photos/200/300.jpg?random=2|サトウ
3|田中|https://picsum.photos/200/300.jpg?random=3|タナカ
最後にスキーマを変更することで、NOT NULL 制約を付与します。
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 078feff..24c96d7 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -8,8 +8,9 @@ datasource db {
}
model Member {
id Int @id @default(autoincrement())
name String
+ kana String?
avatar String
@@map("members")
npx prisma db push
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": SQLite database "dev.db" at "file:./dev.db"
🚀 Your database is now in sync with your Prisma schema. Done in 8ms
✔ Generated Prisma Client (v5.4.2) to ./node_modules/@prisma/client in 55ms
これでフィールドの追加は完了です。テーブル定義が以下のように変更されました!
CREATE TABLE IF NOT EXISTS "members" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL,
+ "kana" TEXT NOT NULL,
"avatar" TEXT NOT NULL
);
おわりに
最近はもっぱらフロント周辺の技術を勉強していたので、久しぶりに DB 周りを触れて楽しかったです 🌝