简体   繁体   中英

Cannot delete or update a parent row: a foreign key constraint fails - MYSQL

I'm getting this error when trying to delete a user from the database, I know it's doing this because the user I'm trying to delete is a foreign key in the appointments table, but I don't know how to correct it or where I have gone wrong. Not sure if it changes anything but just incase I created the tables using laravel

Users table

CREATE TABLE `users` (
  `id` int(10) UNSIGNED NOT NULL,
  `firstname` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
  `surname` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
  `address` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
  `postcode` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
  `email` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
  `password` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
  `dateofbirth` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
  `role` tinyint(4) NOT NULL,
  `remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Appointments table

 CREATE TABLE `appointments` (
      `id` int(10) UNSIGNED NOT NULL,
      `time` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
      `date` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
      `created_at` timestamp NULL DEFAULT NULL,
      `updated_at` timestamp NULL DEFAULT NULL,
      `doctor_id` int(10) UNSIGNED NOT NULL,
      `user_id` int(10) UNSIGNED NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

    ALTER TABLE `appointments`
      ADD PRIMARY KEY (`id`),
      ADD KEY `appointments_doctor_id_foreign` (`doctor_id`),
      ADD KEY `appointments_user_id_foreign` (`user_id`);

    ALTER TABLE `appointments`
      ADD CONSTRAINT `appointments_doctor_id_foreign` FOREIGN KEY (`doctor_id`) REFERENCES `doctors` (`id`),
      ADD CONSTRAINT `appointments_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`);

You get this error because the user you would like to delete has associated records within the appointments table. You have 2 options:

  1. Delete the associated records from the appointments table first with a separate delete statement.

  2. Add on delete cascade option to appointments_user_id_foreign foreign key. This option will automatically remove any associated records from the appointments table for the user to be deleted when you delete the user's record.

The modified fk statement looks like as follows:

... ADD CONSTRAINT `appointments_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;

The solution proposed by @Nebster technically removes the error message, but also enables having orphan records within the appointments table - appointments related to deleted users. Therefore, removing the foreign key is not a sensible option in my opinion.

SET FOREIGN_KEY_CHECKS=0; – to disable them

SET FOREIGN_KEY_CHECKS=1; – to re-enable them

When you're deleting from phpMyAdmin, just uncheck enable foreign key checks at bottom

在此处输入图片说明

Seems like your Foreign key in Appointments table has On delete: Restrict option. Change the Constraint appointments_user_id_foreign to On delete: Cascade and you should be able to delete Users while preserving Foreign key.

ALTER TABLE "appointments" DROP FOREIGN KEY "appointments_user_id_foreign";

ALTER TABLE "appointments" ADD CONSTRAINT "appointments_user_id_foreign" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE;

You cannot simply delete a user from table users. It is being referenced by the appointments table as foreign key index. I think it is fair enough that when a user is deleted all his references should be deleted from other tables.

For your scenario, you can improve your database design. You can make the foreign key column in appointments table optional. So if user is deleted the corresponding record's user_id can be set as NULL. But it is meaningless to store appointments for those users who no longer exist in the system. Another approach be to before deleting that user, delete all his corresponding references from appointments table and then delete the reference from users table

If you want a temporary solution, then try the following

SET FOREIGN_KEY_CHECKS=OFF; -- to disable foreign key checks
//drop the table and then
SET FOREIGN_KEY_CHECKS=ON; -- to re-enable foreign key checks

There are a couple of options, but in the end there are really only two main options:

  1. Add on delete cascade meaning that when user is deleted appointments relating to that user should also be deleted as suggested by Shadow (point number two)
  2. Add on delete set null meaning that when user is deleted appointments user_id relating to that user should be set to null (though you will have to change user_id int(10) UNSIGNED NOT NULL to user_id int(10) UNSIGNED DEFAULT NULL

Which solution should one choose?

Lets say this is for a clinic and the clinic gets a request from a user to delete him from the db. That is fine, happens all the time. But the clinic still wants to keep history of all the appointments in the db. In this case you would go with solution number 2. In this way when user is deleted you will still have the appointment in the db, but the user_id will be null as that user does not exist anymore. If the clinic does not care about history of the appointments then you can go with solution number one. Though one can also set user fields to null instead of deleting the row completely, and in that case you would go with solution number one as one would never actually need to fully delete a user record.

I had the same exception. I could solve the issue with changing to CascadeType.DETACH in my parent class.

So in your case it would be

public class AppointmentsEntity {

    @JoinColumn(name = "USER_ID", referencedColumnName = "ID")
    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.DETACH)
    private User user;

}

Btw: You better use singular names for database table names.

Actually, it depends on your Data-Model and you should ask you the question whether the child entity should/can exist without the parent. This answers how you have the treat the child entity.

I found a solution for that issue with Typeorm MysQL: You can set 'createForeignKeyConstraints' to FALSE.

@OneToOne(type => Task, { 
  cascade: true, onDelete: 'CASCADE', createForeignKeyConstraints: false 
})
@JoinColumn()
taskDetails: Task
SET FOREIGN_KEY_CHECKS=OFF; -- to disable foreign key checks
//drop the table and then
SET FOREIGN_KEY_CHECKS=ON; -- to re-enable foreign key checks

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM