说我有一堆人有多个电话号码。在MySQL数据库中,我将具有一个人与人表和一个具有多对一关系的电话号码表。 现在,我想将其中一个号码设为主要电话号码,并且每人只允许使用一个主要号码。我将如何建模?
答案 0 :(得分:1)
“仅一个主要电话号码”就比较棘手。一种方式使用触发器。其他数据库提供基于表达式的索引。这很棘手,因为:
但是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
。
答案 1 :(得分:0)
您可以尝试以下提到的设计:
Person (Id (PK),name,....)
TelephoneNumber (Id(PK), telNo, PersonId(FK))
PrimaryTelNo (PersonId(FK), TelId(FK))
您可以创建一个表,显示TelId
和PersonId
的映射,并将TelId
和PersonId
的组合声明为composite primary key
答案 2 :(得分:0)
尝试以下模式。这样可以防止试图为每个人分配多个主要号码的条目。
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);
这将使DB可以为每个人管理一个单一的主要电话号码。例如,如果您尝试为Michael Jones分配另一个主要电话号码:
将电话号码(电话号码,person_id,is_primary)插入VALUES('0123211234',1,1);
您将收到“键'idx_person_primary'的重复条目'1-1'”错误。
答案 3 :(得分:0)
您应该创建仅包含两个字段的第三个表person_primary_number
:
person_id
phone_number_id
在此表中,您应该插入此人的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
此解决方案的唯一问题是您可以将其他人的号码分配为主电话。
答案 4 :(得分:0)
最简单的方法是将“第一个”作为主要对象,但这在您要更改哪个是主要对象时变得很棘手。在那种情况下,我相信你可以做到这一点...
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和null,但是虽然可以有多个null,但每个人只能有一个“ 1”。但是,此解决方案并不排除所有数字都不是主要数字的可能性!
答案 5 :(得分:0)
这违反了架构设计的强大原则-不要将列表打包到单元格中。但是...
请考虑使用一个awk -v q="'" '{for(i=2;i<=NF;i++)if($i~/^[^-]/)$i=q $i q}7' file
列,该列的逗号以“主要”电话号码开头,并以备用号码开头。
请注意,应用程序将负责将列表放在一起,并处理更新。或者,您也可以通过提供一个要求输入“电话号码(从首选电话与您联系的电话号码;请用逗号分隔)”的UI,将其推回给用户。