Как я могу создать внешний ключ с помощью On Delete = Set Null?

РЕШЕНО: Удалив атрибут первичного ключа из внешних ключей.

Я создаю базу данных SQL для школы, чтобы отслеживать учителей, студентов, группы и платежи.

Я установил каскадирование всех внешних ключей при обновлении (поскольку я считаю, что это будет лучший способ), но я хочу установить для них значение null при удалении (то есть: если кто-то удаляет группу, студенты могут быть назначены в другую группу с обновлением), но сервер выдает мне это сообщение в таблицах grupo и grupoalumno, когда я пытаюсь создать базу данных:

Error: 150 "Foreign key constraint is incorrectly formed".

У меня есть внешние ключи, не отмеченные нулевым значением (что означает, что внешний ключ может быть нулевым значением), и, насколько я понял, решение состоит в том, чтобы установить первичные ключи, на которые ссылаются, как имеющие значение NULL, что заставляет меня сомневаться, что это было бы неплохо иметь PK null.

Я также подумал об ограничении удаления и использовании только обновлений (то есть: редактирование группы до тех пор, пока она не станет правильной, вместо ее удаления), но я думаю, что иметь возможность фактически удалить группу без каскадирования всей базы данных было бы разумно.

Я создаю таблицы в том порядке, в котором они должны быть (то есть: я не создаю таблицу, которая ссылается на ключ, который еще не был создан. Как я могу создать внешний ключ с помощью On Delete = Set Null?

Я использую PHPMyAdmin и MySQL Workbench. Я считаю, что MySQL экспортирует базу данных с InnoDB в качестве движка.

Надеюсь, я объяснил. Заранее спасибо. Надеюсь многому научиться!

Код:

-- MySQL Script generated by MySQL Workbench
-- 10/29/18 21:25:26
-- Model: New Model    Version: 1.0
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';

-- -----------------------------------------------------
-- Schema celex
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `celex` DEFAULT CHARACTER SET utf8 COLLATE utf8_spanish_ci ;
USE `celex` ;

-- -----------------------------------------------------
-- Table `celex`.`Grupo`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `celex`.`Grupo` (
  `idGrupo` INT NOT NULL AUTO_INCREMENT,
  `idioma` VARCHAR(45) NOT NULL,
  `nivel` VARCHAR(45) NOT NULL,
  `horarioInicio` TIME NULL,
  `horarioTermino` TIME NULL,
  PRIMARY KEY (`idGrupo`))
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `celex`.`Alumno`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `celex`.`Alumno` (
  `idAlumno` INT NOT NULL AUTO_INCREMENT,
  `nombre` VARCHAR(45) NOT NULL,
  `primerApellido` VARCHAR(45) NOT NULL,
  `segundoApellido` VARCHAR(45) NOT NULL,
  `email` VARCHAR(45) NOT NULL,
  `telefono` VARCHAR(45) NULL,
  `edad` INT NULL,
  `procedencia` VARCHAR(45) NULL,
  `fechaIngreso` DATE NOT NULL,
  `nivelIngreso` VARCHAR(45) NOT NULL,
  `moduloIngreso` INT NOT NULL,
  `nivelColocacion` VARCHAR(45) NULL,
  `moduloColocacion` INT NULL,
  PRIMARY KEY (`idAlumno`))
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `celex`.`Periodo`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `celex`.`Periodo` (
  `idPeriodo` INT NOT NULL AUTO_INCREMENT,
  `nombre` VARCHAR(45) NULL,
  `inicio` DATE NOT NULL,
  `termino` DATE NOT NULL,
  PRIMARY KEY (`idPeriodo`))
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `celex`.`GrupoAlumno`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `celex`.`GrupoAlumno` (
  `idGrupoAlumno` INT NOT NULL AUTO_INCREMENT,
  `modulo` INT NOT NULL,
  `calificacionParcial` DOUBLE NULL,
  `calificacionFinal` DOUBLE NULL,
  `calificacionExtra` DOUBLE NULL,
  `Periodo_idPeriodo` INT NULL,
  `Grupo_idGrupo` INT NULL,
  `Alumno_idAlumno` INT NULL,
  PRIMARY KEY (`idGrupoAlumno`, `Periodo_idPeriodo`, `Grupo_idGrupo`, `Alumno_idAlumno`),
  INDEX `fk_Grupo_has_Alumno_Alumno1_idx` (`Alumno_idAlumno` ASC),
  INDEX `fk_Grupo_has_Alumno_Grupo_idx` (`Grupo_idGrupo` ASC),
  INDEX `fk_GrupoAlumno_Periodo1_idx` (`Periodo_idPeriodo` ASC),
  CONSTRAINT `fk_Grupo_has_Alumno_Grupo`
    FOREIGN KEY (`Grupo_idGrupo`)
    REFERENCES `celex`.`Grupo` (`idGrupo`)
    ON DELETE SET NULL
    ON UPDATE CASCADE,
  CONSTRAINT `fk_Grupo_has_Alumno_Alumno1`
    FOREIGN KEY (`Alumno_idAlumno`)
    REFERENCES `celex`.`Alumno` (`idAlumno`)
    ON DELETE SET NULL
    ON UPDATE CASCADE,
  CONSTRAINT `fk_GrupoAlumno_Periodo1`
    FOREIGN KEY (`Periodo_idPeriodo`)
    REFERENCES `celex`.`Periodo` (`idPeriodo`)
    ON DELETE SET NULL
    ON UPDATE CASCADE)
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `celex`.`PeriodoAlumno`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `celex`.`PeriodoAlumno` (
  `idPeriodoAlumno` INT NOT NULL AUTO_INCREMENT,
  `cuota` TINYINT(1) NULL,
  `Periodo_idPeriodo` INT NULL,
  `Alumno_idAlumno` INT NULL,
  PRIMARY KEY (`idPeriodoAlumno`, `Periodo_idPeriodo`, `Alumno_idAlumno`),
  INDEX `fk_Periodo_has_Alumno_Alumno1_idx` (`Alumno_idAlumno` ASC),
  INDEX `fk_Periodo_has_Alumno_Periodo1_idx` (`Periodo_idPeriodo` ASC),
  CONSTRAINT `fk_Periodo_has_Alumno_Periodo1`
    FOREIGN KEY (`Periodo_idPeriodo`)
    REFERENCES `celex`.`Periodo` (`idPeriodo`)
    ON DELETE SET NULL
    ON UPDATE CASCADE,
  CONSTRAINT `fk_Periodo_has_Alumno_Alumno1`
    FOREIGN KEY (`Alumno_idAlumno`)
    REFERENCES `celex`.`Alumno` (`idAlumno`)
    ON DELETE SET NULL
    ON UPDATE CASCADE)
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `celex`.`Maestro`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `celex`.`Maestro` (
  `idMaestro` INT NOT NULL AUTO_INCREMENT,
  `nombre` VARCHAR(45) NOT NULL,
  `primerApellido` VARCHAR(45) NOT NULL,
  `segundoApellido` VARCHAR(45) NOT NULL,
  `email` VARCHAR(45) NOT NULL,
  `telefono` VARCHAR(45) NULL,
  PRIMARY KEY (`idMaestro`))
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `celex`.`GrupoMaestro`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `celex`.`GrupoMaestro` (
  `idGrupoMaestro` INT NOT NULL AUTO_INCREMENT,
  `Grupo_idGrupo` INT NULL,
  `Maestro_idMaestro` INT NULL,
  PRIMARY KEY (`idGrupoMaestro`, `Grupo_idGrupo`, `Maestro_idMaestro`),
  INDEX `fk_Grupo_has_Maestro_Maestro1_idx` (`Maestro_idMaestro` ASC),
  INDEX `fk_Grupo_has_Maestro_Grupo1_idx` (`Grupo_idGrupo` ASC),
  CONSTRAINT `fk_Grupo_has_Maestro_Grupo1`
    FOREIGN KEY (`Grupo_idGrupo`)
    REFERENCES `celex`.`Grupo` (`idGrupo`)
    ON DELETE SET NULL
    ON UPDATE CASCADE,
  CONSTRAINT `fk_Grupo_has_Maestro_Maestro1`
    FOREIGN KEY (`Maestro_idMaestro`)
    REFERENCES `celex`.`Maestro` (`idMaestro`)
    ON DELETE SET NULL
    ON UPDATE CASCADE)
ENGINE = InnoDB;


SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

изменить: добавление запроса для создания базы данных.

Нет. Первичные ключи никогда не должны быть нулевыми. Внешний ключ может ссылаться на ненулевой столбец. Вот как это делается на самом деле. Ваша ошибка могла быть по другой причине.

Phiter 29.10.2018 21:54

Увидев схему вашей базы данных, я чувствую, что вы можете просто удалить строки из GrupoAluno, поскольку это сводная таблица, которая связывает Aluno и Grupo, чтобы отсоединить учащегося от группы.

Phiter 29.10.2018 21:56

Вот почему я смущен, нет смысла иметь нулевой PK, но я не понимаю, почему mysql не принимает установку ограничения удаления для установки null. Я все перепроверяю, но сейчас у меня может быть туннельное зрение. Подожду пару часов, чтобы узнать причину.

David Cristerna 29.10.2018 21:58

Я собираюсь изучить эту возможность (об обновлении таблиц с учетом вашего предложения). Я придумал эту модель, потому что в течение года группы будут сильно меняться. Спасибо за предложение.

David Cristerna 29.10.2018 22:01

@Phiter Я собираюсь попробовать сделать таблицу n-n с maestro и grupo. Чтобы все отношения выходили за рамки основных таблиц, и посмотреть, поможет ли это.

David Cristerna 29.10.2018 22:06
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
5
734
1

Ответы 1

При установке ограничения внешнего ключа, в дополнение к каскаду при обновлении, вы можете установить значение null при удалении следующим образом:

FOREIGN KEY (Grupo_idGrupo) REFERENCES Grupo (idGrupo) 
ON DELETE SET NULL ON UPDATE CASCADE

Да, но ошибка продолжает выскакивать. Я обновил вопрос, добавив дополнительную информацию.

David Cristerna 30.10.2018 04:40

Другие вопросы по теме