MySQL один ко многим с основным выбором - PullRequest
0 голосов
/ 25 октября 2018

Скажем, у меня есть группа людей с несколькими телефонными номерами.В базе данных MySQL у меня будет таблица Person и таблица Phone Number с отношением «многие к одному».Теперь я хочу сделать один из этих номеров основным номером телефона и разрешить только один основной номер на человека.Как бы я смоделировал это?

Ответы [ 6 ]

0 голосов
/ 26 октября 2018

Это нарушает строгий принцип проектирования схемы - не упаковывайте список в ячейку.Но ...

  • Если вам нужно отобразить номер телефона только тому человеку, который будет выполнять вызов, и
  • Если этому человеку, возможно, нужно увидеть неосновные номера, затем

Возможно, у вас есть столбец VARCHAR(100), в котором есть commalist, начинающийся с «основного» номера телефона и заканчивающийся альтернативными номерами.

Обратите внимание, что приложение ответственнодля составления списка и работы с обновлениями.Или вы можете отправить это обратно пользователю, предоставив пользовательский интерфейс, который запрашивает «номера телефонов, начиная с номера телефона, на который вы предпочитаете звонить; разделяйте их запятыми».

0 голосов
/ 25 октября 2018

«Ровно один основной номер телефона» сложно.Один способ использует триггеры.Другие базы данных предлагают индексы на основе выражений.Это сложно, потому что:

  • Ограничение охватывает две таблицы.
  • Гарантировать точную "единообразие" для всех обновлений сложно.

Но один методв MySQL это близко и не использует триггеры:

create table persons (
    personId int auto_increment primary key,
    primary_personPhonesId int,
    . . .
);

create table personPhones (
    personPhonesId int auto_increment primary key,
    personId int,
    . . .
    foreign key (personId) references persons (personId),
    unique (personId, personPhonesId)  -- seems redundant but needed
);

alter table persons
    add foreign key (personId, primary_personPhonesId) on personPhones(personId, personPhonesId);

Заманчиво объявить primary_personPhonesId как not null.Однако это затрудняет вставку строк в две таблицы.

Альтернативный метод использует вычисляемые столбцы:

create table persons (
    personId int auto_increment primary key,
    . . .
);

create table personPhones (
    personPhonesId int auto_increment primary key,
    personId int,
    isPrimary boolean,
    . . .
    foreign key (personId) references persons (personId),
    primaryId as (case when isPrimary then personPhonesId end),
    unique(primaryId)
);

Подобно предыдущему решению, это не гарантирует, что isPrimaryвсегда установлен.

0 голосов
/ 25 октября 2018

Самый простой способ - сделать «первый» первичным, но это становится сложнее, когда вы хотите изменить, какой из них первичный.В этом случае, я полагаю, вы можете сделать это ...

CREATE TABLE my_table
(person_id INT NOT NULL
,phone VARCHAR(12) not null
,is_primary enum('1') null 
,primary key(person_id,phone)
, unique (person_id,is_primary)
);

INSERT INTO my_table VALUES
(1,'123',1),
(1,'234',null),
(1,'345',null),
(2,'456',null),
(2,'567',1),
(2,'678',null);

Итак, перечисление допускает значения 1 и ноль, но хотя может быть несколько нулей, может быть только один '1' начеловек.Однако это решение не исключает возможности того, что ни одно из чисел не является первичным!

0 голосов
/ 25 октября 2018

Вы должны создать третью таблицу person_primary_number только с двумя полями:

person_id
phone_number_id

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

Другой способ - добавить primary_number_id непосредственно в таблицу person.Это, наверное, самое простое решение.

Тогда у вас должно быть:

person
—————-
id (primary key int autoincrement)
primary_number_id (foreign key for phone_number.id)
name
... 

phone_number
———————————-
id (primary key int autoincrement)
person_id (foreign key for person.id)
phone_number

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

0 голосов
/ 25 октября 2018

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

CREATE TABLE person (
  `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `first_name` VARCHAR(50) NOT NULL,
  `last_name` VARCHAR(50) NOT NULL,
  PRIMARY KEY(`id`)
);

CREATE TABLE phonenumber (
  `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `phonenumber` VARCHAR(10) NOT NULL,
  `person_id` INT(11) UNSIGNED NOT NULL,
  `is_primary` ENUM('1'),
  PRIMARY KEY(`id`),
  UNIQUE KEY idx_person_primary (`person_id`, `is_primary`),
  UNIQUE KEY idx_person_phone (`phonenumber`, `person_id`)
);   

INSERT INTO person (first_name, last_name) VALUES ('Michael', 'Jones');
INSERT INTO phonenumber (phonenumber, person_id, is_primary) VALUES ('9876543210', 1, 1);
INSERT INTO phonenumber (phonenumber, person_id, is_primary) VALUES ('1234567890', 1, NULL);
INSERT INTO phonenumber (phonenumber, person_id, is_primary) VALUES ('1234567891', 1, NULL);

Это позволит БД контролировать один основной номер телефона для каждого человека.Например, если вы попытаетесь назначить другой основной номер телефона Майклу Джонсу:

INSERT INTO номер телефона (номер телефона, person_id, is_primary) VALUES ('0123211234', 1, 1);

Вы будетеполучить «Дублирующую запись« 1-1 »для ключа« idx_person_primary »».

http://sqlfiddle.com/#!9/dbb3c7/1

0 голосов
/ 25 октября 2018

Вы можете попробовать приведенный ниже дизайн:

Person (Id (PK),name,....)
TelephoneNumber (Id(PK), telNo, PersonId(FK))
PrimaryTelNo (PersonId(FK), TelId(FK))

Вы можете создать таблицу с отображением TelId и PersonId и объявить комбинацию TelId и PersonId как composite primary key

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...