💻

Prismaでレコードを保持したままテーブル名を変更する

に公開

EMのどんちゃんです。

HCCloudの開発では、DBにはPostgreSQLを使用しています。
ORMにはPrismaを採用しています。

ある時、機能名を変更することになり、実装との整合性を取るためにテーブル名を変更するという決断をしました。

GAされているサービスで、テーブル名を変更することはリスキーなので好ましくないですが、規模が小さいうちに、事前にバックアップを取った上で行うことにしました。

userscustomerテーブルに変更してみよう

今回は記事用に、いくつかのレコードがあるusersテーブルを、単数系にしつつcustomerテーブルに変更する場合を想定します。

Prismaでテーブル名を変更することは可能だが…

Prismaのスキーマファイルでは、@@map("テーブル名")を使用することでDBに作成するテーブル名を指定することができます。

https://www.prisma.io/docs/orm/prisma-schema/data-model/database-mapping#map-collection--table-names

「じゃあここを変更したらええんちゃうの🧐」と思いますがそうはいきません。

yarn prisma migrate dev --create-onlyコマンドを実行して生成されるSQLがこちら(yarnを使ってます)

/*
  Warnings:

  - You are about to drop the `users` table. If the table is not empty, all the data it contains will be lost.

*/
-- DropForeignKey
ALTER TABLE "users" DROP CONSTRAINT "users_company_id_fkey";

-- DropTable
DROP TABLE "users";

-- CreateTable
CREATE TABLE "customer" (
    "id" SERIAL NOT NULL,
    "first_name" TEXT NOT NULL,
    "last_name" TEXT NOT NULL,
    "email" TEXT NOT NULL,
    "company_id" INTEGER NOT NULL,
    "role" TEXT,
    "thumbnail_url" TEXT,
    "last_login_at" TIMESTAMPTZ(6),

    CONSTRAINT "customer_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "customer_email_key" ON "customer"("email");

-- AddForeignKey
ALTER TABLE "customer" ADD CONSTRAINT "customer_company_id_fkey" FOREIGN KEY ("company_id") REFERENCES "company"("id") ON DELETE CASCADE ON UPDATE CASCADE;

You are about to drop the users table. If the table is not empty, all the data it contains will be lost.

テーブルをdropしてからcreateするという挙動をします

これではレコードを維持したままリネームできないので工夫を加える必要があります。

Migrationファイルを加工

migrationファイルが生成されたら、それを下記のように書き換えます。
Dropされないように、制約や、シーケンスキー名、最後にテーブル名を変更するSQLにします。
なお、今回はPostgreSQLを前提としているので、他のRDBMSを利用している場合は読み替えてください。

ここを正確に行うようにしておきましょう。

-- RenamePrimaryKey
ALTER TABLE "users" RENAME CONSTRAINT "users_pkey" TO "customer_pkey";

-- RenameForeignKey
ALTER TABLE "users" RENAME CONSTRAINT "users_company_id_fkey" TO "customer_company_id_fkey";

-- Rename Sequence
ALTER SEQUENCE users_id_seq RENAME TO customer_id_seq;

-- RenameIndex
ALTER INDEX "users_email_key" RENAME TO "customer_email_key";

-- Rename Table
ALTER TABLE "users" RENAME TO "customer";

再度migrationを実行

yarn prisma migrate dev

これで、レコードを保持したままテーブル名の変更ができます。

余計なMigrationファイルを作りたくない場合

上記の方法の場合、--create-onlyと、適用時に同じようなMigrationファイルが2つできてしまいます。

それを回避するには、次の方法を取れます(DBに直接SQLを実行できる場合に可能です)

SQLを実行

Migrationファイルを加工 で作成したSQLをRDBMSから実行します。

Migrationを解決

次に、Prismaと整合性を取るために prisma migrate dev --create-onlyで作成したMigrationファイルを解決状態にします。

yarn prisma migrate resolve --applied {migrationディレクトリ名}

例:

yarn prisma migrate resolve --applied 20250909063523_rename_users_to_customer

本番環境への適用

ローカル環境では、上記の方法でテーブル名の変更、Migrationファイルの作成が完了します。

通常通り、CI/CDなどで下記のコマンドで本番環境もデータを保持したままリネームできます🚀

yarn prisma migrate deploy

FYI

https://www.prisma.io/docs/orm/prisma-migrate/workflows/customizing-migrations

HCプロデューステックブログ

Discussion