経緯
Laravel8でsail artisan migrate
を実行したときに出たエラーです。Usersテーブル(親テーブル)と、外部キーuser_idを持つPostsテーブル(子テーブル)があるとして書いていきます。2つのテーブルのためのマイグレーションファイルを作り、テーブルを設定し、sail artisan migrate
と実行すると
SQLSTATE[HY000]: General error: 1824 Failed to open the referenced table 'users' (SQL: alter table `posts` add constraint `posts_user_id_foreign` foreign key (`user_id`) references `users` (`id`))
というエラーが出ました。
原因
エラーの内容は、「『posts』テーブルは外部キー『user_id』を持ってて『users』テーブルを参照しようとしているけど見つからないよ」というものです。これは、Postsテーブル(子テーブル)のマイグレーションファイルを作った後に、Usersテーブル(親テーブル)のマイグレーションファイルを作ったことが原因です。
本来は、
①usersテーブルが作成される。
②postsテーブルが作成される。
③user_idがusersテーブルを参照する。
という流れなのですが、このときは
①postsテーブルが作成される。
②user_idがusersテーブルを参照する。。。
となり、usersテーブルを参照したいけど、まだusersテーブルは作ってないから出来ない!という状態になってしまっています。
解決策
先にUsersテーブル(親テーブル)後でPostsテーブル(子テーブル)を作ればPostsテーブルはUsersテーブルを参照できて、問題が解決します。ですので、sail artisan migrate:rollback
(後述しますが、このときにもエラー発生します。)でロールバックした後に、現在の状態では、マイグレーションファイルの名前の日付が、子テーブルのほうが早くなっていますが、日付順を入れ替えます。
before
2021_09_07_234727_create_posts_table.php
2021_09_08_234727_create_users_table.php
after
2021_09_08_234727_create_users_table.php
2021_09_09_234727_create_posts_table.php
これで再度マイグレーションをすると無事成功します。
ロールバック時のエラー
ロールバックを実行しようとすると、
SQLSTATE[HY000]: General error: 3730 Cannot drop table 'users' referenced by a foreign key constraint 'posts_user_id_foreign' on table 'posts'. (SQL: drop table if exists `users`)
というエラーが出るかもしれません。(この例では起きないですが)。これは、Postsテーブル(子テーブル)が消されるまえにUsersテーブル(親テーブル)を消そうとしているため、「Postsテーブルのuser_idがUsersテーブルを参照してるから消せないよ」と言っているものです。usersテーブルのマイグレーションファイルにある、down時の設定をし忘れていることが原因で、ロールバック時に子テーブルを先に削除するように設定すると解決します。
before
public function down()
{
Schema::dropIfExists('users');
}
after
public function down()
{
Schema::dropIfExists('posts');
Schema::dropIfExists('users');
}
参考
https://stackoverflow.com/questions/52377469/failed-to-open-the-referenced-table
https://stackoverflow.com/questions/32524101/laravel-change-migration-order