Сохранять внешний ключ нулевым, если информация легко определяется?

#mysql #sql #database-design #foreign-keys

#mysql #sql #дизайн базы данных #внешние ключи

Вопрос:

У меня есть следующие таблицы:

 TABLE country
(
    country_id int not null,
    name varchar(32) not null,
    primary key (country_id),
    unique key (name)
);

TABLE place
(
    place_id int not null,
    name varchar(32) not null,
    country_id int not null,
    primary key (place_id),
    unique key (country_id, name)
);

TABLE image
(
    image_id int not null,
    title varchar(75) not null,
    caption varchar(500) not null,
    filename varchar(29) not null,
    country_id int,
    place_id int,
    primary key (image_id),
    unique key (filename)
);
 

Изображение может иметь страну (или нет) или место (или нет).

Допустим, у меня есть запись в country таблице:

 23 | Spain |
 

И места в place таблице:

 3 | Madrid | 23
6 | Barcelona | 23
 

Я хочу image пометить страну Spain и место Barcelona

В image таблице я должен ввести country_id и place_id или просто place_id , поскольку страна уже определена по place_id?

Комментарии:

1. Совет: рассмотрите возможность использования VARCHAR(255) в качестве поля строкового типа общего назначения по умолчанию и переопределяйте его более длинными или более короткими ограничениями, только если у вас есть веская причина. Многие установки MySQL будут автоматически усекать любые данные, которые не подходят, что приводит к потере данных, жалобам пользователей и другим серьезным проблемам. Имена и адреса электронной почты довольно часто на удивление длинные, поэтому важно учитывать их.

Ответ №1:

Полиморфные отношения нелегко моделировать в реляционной базе данных.

Здесь я бы предложил другой подход, который вы настроили: создайте две разные таблицы мостов для изображений — одну для стран, а другую для мест.

Это будет выглядеть так:

 create table countries (
    country_id int primary key,
    ...
);

create table places (
    place_id int primary key,
    ...
);

create table images (
    image_id int primary key,
    ...
);

create table image_countries (
    image_id   int references images(image_id),
    country_id int references countries(country_id),
    primary key (image_id, country_id)
);

create table image_places (
    image_id   int references images(image_id),
    place_id   int references places(place_id),
    primary key (image_id, place_id)
);
 

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

Ответ №2:

Измените свой умственный фокус. Сосредоточьтесь на «месте», связанном с изображением. Затем сделайте places работу как для «Испании», так и для «Мадрида, Испания». Не пытайтесь перепрыгнуть мимо places , чтобы добраться до countries .

Итак, в places , разрешите пустое name с непустым country для указания «Испания».

Я бы использовал стандартные 2-буквенные коды стран вместо 4-байтового INT. Тогда я бы либо отобразил «ES» с изображениями для Испании, либо создал таблицу поиска, подобную вашей текущей countries .