Могут ли столбцы таблицы с внешним ключом быть NULL? - PullRequest
189 голосов
/ 03 марта 2010

У меня есть таблица, в которой есть несколько столбцов идентификаторов для других таблиц.

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

(Вероятно, это зависит от сервера базы данных, я использую тип таблицы MySQL & InnoDB)

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

Ответы [ 6 ]

194 голосов
/ 03 марта 2010

Да, вы можете применять ограничение только тогда, когда значение не равно NULL. Это легко проверить на следующем примере:

CREATE DATABASE t;
USE t;

CREATE TABLE parent (id INT NOT NULL,
                     PRIMARY KEY (id)
) ENGINE=INNODB;

CREATE TABLE child (id INT NULL, 
                    parent_id INT NULL,
                    FOREIGN KEY (parent_id) REFERENCES parent(id)
) ENGINE=INNODB;


INSERT INTO child (id, parent_id) VALUES (1, NULL);
-- Query OK, 1 row affected (0.01 sec)


INSERT INTO child (id, parent_id) VALUES (2, 1);

-- ERROR 1452 (23000): Cannot add or update a child row: a foreign key 
-- constraint fails (`t/child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY
-- (`parent_id`) REFERENCES `parent` (`id`))

Первая вставка пройдет, потому что мы вставляем NULL в parent_id. Вторая вставка завершается неудачно из-за ограничения внешнего ключа, поскольку мы попытались вставить значение, которого нет в таблице parent.

24 голосов
/ 19 декабря 2012

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

3 голосов
/ 03 марта 2010

Да, это будет работать так, как вы ожидаете. К сожалению, у меня, похоже, возникают проблемы с тем, чтобы найти явное утверждение об этом в руководстве MySQL .

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

1 голос
/ 18 марта 2019

Другим способом было бы вставить элемент DEFAULT в другую таблицу. Например, любая ссылка на uuid = 00000000-0000-0000-0000-000000000000 в другой таблице будет указывать на отсутствие действий. Вам также необходимо установить все значения для этого идентификатора как «нейтральные», например, 0, пустая строка, ноль, чтобы не влиять на логику кода.

1 голос
/ 08 марта 2019

Выше работает, но это не так. Обратите внимание на УДАЛЕННЫЙ КАСКАД

CREATE DATABASE t;
USE t;

CREATE TABLE parent (id INT NOT NULL,
                 PRIMARY KEY (id)
) ENGINE=INNODB;

CREATE TABLE child (id INT NULL, 
                parent_id INT NULL,
                FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE

) ENGINE=INNODB;


INSERT INTO child (id, parent_id) VALUES (1, NULL);
-- Query OK, 1 row affected (0.01 sec)
0 голосов
/ 28 марта 2019

Я тоже застрял в этом вопросе. Но я решил просто, определив внешний ключ как unsigned integer. Найдите приведенный ниже пример -

CREATE TABLE parent (
   id int(10) UNSIGNED NOT NULL,
    PRIMARY KEY (id)
) ENGINE=INNODB;

CREATE TABLE child (
    id int(10) UNSIGNED NOT NULL,
    parent_id int(10) UNSIGNED DEFAULT NULL,
    FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE
) ENGINE=INNODB;
...