如何建模一对多的关系,这是一种有条件的

时间:2015-07-20 13:28:12

标签: sqlite relational-database entity-relationship

我是sql和数据建模的初学者。我正在经历Zed Shaw的故事SQL the hard way。除了完成练习,我还试着自己弄清楚一些事情。沿着教程,我被要求创建一个宠物桌。我想将宠物连接到fur_color表来跟踪宠物皮毛的颜色。

我的问题是,并非所有宠物(如鸟类)都有毛皮。我只想为毛皮宠物保存皮毛颜色。在我看来,有一些潜在的条件(宠物有毛皮)。

到目前为止我的解决方案,假设关系是一对多的关系(一只宠物可以有一种颜色,一种颜色可以有很多宠物):我创建了一个新的表fur_colour,其属性为id,id_pet和颜色。我想知道这是否正确,因为我每次都为每条记录存储颜色。

CREATE TABLE pet (
    id INTEGER PRIMARY KEY,
    name TEXT,
    breed TEXT,
    dead INTEGER
);
CREATE TABLE fur_colour (
    id INTEGER PRIMARY KEY,
    pet_id INTEGER,
    colour TEXT
);
INSERT INTO pet (id, name, breed)
    VALUES  (1,"Santa's Little Helper", 'dog'),
            (2,'Snowball II', 'cat'),
            (3,'Canary M. Burs', 'bird');
INSERT INTO fur_colour (id, pet_id, colour)
    VALUES  (1, 1, 'brown'),
            (2, 2, 'black');
SELECT pet.name, fur_colour.colour FROM pet, fur_colour WHERE
    pet.id = fur_colour.pet_id;

另一个解决方案是创建一个表颜色,其中存储所有可能的颜色,并使用表fur_colour连接毛发和颜色,我只存储colour_id和pet_id。但到目前为止,我了解到这个解决方案是模拟多对多的关系。

CREATE TABLE pet (
id INTEGER PRIMARY KEY,
name TEXT,
breed TEXT
);
CREATE TABLE fur_colours (
    id INTEGER PRIMARY KEY,
    colour TEXT
);

CREATE TABLE pet_colour (
    id_pet INTEGER,
    id_colour INTEGER
);

INSERT INTO pet (id, name, breed)
    VALUES  (1,"Santa's Little Helper", 'dog'),
            (2,'Snowball II', 'cat'),
            (3,'Canary M. Burs', 'bird');
INSERT INTO fur_colours (id, colour)
    VALUES  (1, 'grey'),
            (2, 'brown'),
            (3, 'white'),
            (4, 'black');

INSERT INTO pet_colour (id_pet, id_colour)
    VALUES  (1, 2),
            (2, 4);

SELECT pet.name, fur_colours.colour FROM pet, fur_colours, pet_colour WHERE
    pet.id = pet_colour.id_pet AND
    fur_colours.id = pet_colour.id_colour;

有没有更好的方法来模拟这种情况?

1 个答案:

答案 0 :(得分:1)

您的第一个解决方案使用英文名称表示颜色。名称不能为颜色制作好的标识符 - 它们需要命名所有内容,可以用各种方式编写(灰色与灰色对比灰色与灰色等等),假设是首选语言,并且不是有效的陈述。但是,如果您有一个固定的值列表,并设置正确的检查约束,则此解决方案可以正常运行。

您的第二个解决方案通过代理号表示颜色。如果您有可接受的颜色列表,这可能会有效。代理ID比名称更稳定,并且具有有效颜色表使得更容易维护(添加/删除颜色需要操纵数据而不是模式)。同样,请确保设置正确的约束以确保有效数据 - 对名称的唯一约束,以及外键约束以防止无效的宠物颜色。

对于更多种颜色,您可以将它们表示为给定颜色空间中的数字。例如,32位整数可以表示RGB值:黑色= 0,红色= 16711680,黄色= 16776960,白色= 16777215.这些可以很容易地从/转换为十六进制。如果你想命名颜色,那么你可以使用像fur_colours这样的表,但是使用RGB值作为标识符而不是代理id。

通常,为每个实体找到一个好的标识符是数据库设计的隐藏技术之一。一个尺码不适合所有人。自然键非常有价值,应该包含在设计中,即使它们不用于主键(但使用它们通常会使数据库更易于使用)。有时键是复合的。经常使用代理ID。人们可以写一整本关于身份和表现的书。

现在,你的fur_colour / pet_colour的表设计有一个问题 - 既不强制关系的基数!如果你将pet_id作为主键(并在fur_colour的情况下删除代理id),那将强制要求宠物只有一种颜色。它是pet_id上的主要/唯一约束,它使它成为一对多(或缺少它使它成为多对多),而不是您的颜色是通过名称还是代理ID来表示。< / p>