Могут ли столбцы таблицы с внешним ключом быть NULL?

178

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

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

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

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

  • 6
    Я не знаю, что такое MySQL, но MS SQL Server позволяет обнулять внешние ключи семантикой, которую вы хотите. Я ожидаю, что это стандартное поведение.
  • 0
    внешний ключ не может быть пустым по умолчанию в mySQL, причина проста: если вы ссылаетесь на что-то и оставляете это значение пустым, вы потеряете целостность данных. когда вы создаете набор таблиц, разрешите пустое значение NOT, а затем примените ограничение внешнего ключа. Вы не можете установить значение null при обновлении, это должно привести к ошибке, но вы можете (вы должны) просто не обновлять этот столбец и обновлять только те поля, которые необходимо изменить.
Теги:
database
foreign-keys

6 ответов

193
Лучший ответ

Да, вы можете принудительно применять ограничение только тогда, когда значение не равно 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.

  • 14
    Родительская таблица также может быть объявлена с идентификатором INT NOT NULL.
  • 0
    @CJDennis Если вы сделаете так, чтобы только одна строка могла иметь нулевой идентификатор, она могла бы использоваться в качестве запасных значений для других строк. (Хотя это может сработать лучше для БД, если вы просто используете больше столбцов.) Ограничение по умолчанию кажется проблемой, если вы хотите узнать позже, было ли значение первоначально установлено как «значение по умолчанию» (с использованием нуля) или установлено на значение, которое оказывается таким же, как «по умолчанию». Имея строку с нулевым идентификатором, вы можете четко указать, что эта строка не должна использоваться как обычная строка, и можете использовать строку как способ предоставления своего рода динамического значения по умолчанию для других строк.
Показать ещё 1 комментарий
21

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

  • 5
    Не могли бы вы установить значение по умолчанию NULL для столбца, чтобы разрешить это?
  • 0
    Да, в большинстве языков NULL отличается от пустой строки. Возможно, тонкий, когда начало, но важно помнить.
Показать ещё 2 комментария
3

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

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

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

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

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
    Что вы подразумеваете под «вышеупомянутым»? Обратите внимание, что если вы ссылаетесь на другой ответ, порядок может измениться.
0

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

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;
0

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню