对于多对多关联,是否有连接表的选项?

时间:2015-02-05 15:23:17

标签: postgresql database-design

假设我有两个表,数据不应该通过使用我的应用程序(即域表)来改变,例如汽车模型颜色一辆车。

models表列出了不同类型的汽车模型。

colors表列出了汽车可以进入的不同颜色类型。

现在,它可能不会立即显现,但两者之间存在关系。 颜色可能仅适用于特定型号,或者更有可能是同一品牌的多个型号。 模型当然没有特定颜色,但它确实附带了我想要存储在数据库中的颜色选择或选择。

因此,它们之间存在多对多关系,这表明我应该将该关系的详细信息存储在连接表中。所以,如果你原谅我自己的符号,它看起来像这样:

Volvo V70 <-> Pearl White
Volvo V70 <-> Emerald Green
Volvo V70 <-> Night Black
Volvo V70 <-> Salmon Pink
Volvo V70 <-> Ocean Blue
Volvo V70 <-> Raspberry Red

Volvo V60 <-> Pearl White
Volvo V60 <-> Emerald Green
Volvo V60 <-> Night Black
Volvo V60 <-> Salmon Pink
Volvo V60 <-> Ocean Blue
Volvo V60 <-> Raspberry Red

...

这是很多重复的文字。如果我能做的话会更容易

[Volvo V70, V60, S60, S40] <-> [Pearl White, Emerald Green, Night Black, Salmon Pink, Ocean Blue, Raspberry Red]

然后转到下一个车型和一组颜色。

是否有可以以任何方式简化此过程的常规联接表的任何选项?

2 个答案:

答案 0 :(得分:2)

  • 如果模型不共享颜色组,那么设计将是一个表:

    model [model] comes in color [color]
    
  • 如果模型共享颜色组,则有两个表:

    model [model] comes in the colors of group [group]
    group [group] has color [color]
    

    这些表与投影连接到第一个表:

    SELECT model, color FROM model_group NATURAL JOIN group_color
    
  • 如果模型除了组或代替组之外可以具有特殊的可用和/或不可用的颜色,则具有异常表。表的组现在是默认颜色(如果有):

    model [model] has default color group [group]
    group [group] has color [color]
    model [model] is exceptionally available in color [color]
    model [model] is exceptionally unavailable in color [color]
    

    然后,异常表分别与JOIN-plus-PROJECT / SELECT UNIONed和MINUSed / EXCEPTed一起表示第一个表:

    SELECT group, color FROM model_default NATURAL JOIN group_colour
    EXCEPT SELECT * FROM model_unavailable
    UNION SELECT * FROM model_available
    

“冗余”不是关于多个地方出现的值。它是关于应用程序的多行描述相同的事情。

每个表(和查询表达式)都有一个关联的填充(命名)空白语句模板(又名谓词)。构成真实语句的行会进入表中。如果你有两个独立的谓词,那么你需要两个表。相关值包含在每一行的行中。

关于应用程序的重做行,请参阅this。 (并在我的其他答案中搜索表格的“声明”或“标准”。)规范化有所帮助,因为它取代了其行以“... AND ...”形式表达事物的表格,其他表格表示“... “分开。请参阅thisthis

如果您共享组并且仅使用单个双列表作为模型和颜色,则其谓词为:

FOR SOME group
    model [model] comes in the colors of group [group]
AND group [group] has color [color]

因此,第二个项目符号从该谓词中删除了一个“AND”,即“多值依赖项”的来源。否则,如果更改模型的组或组的颜色,则必须同时更改多行。 (重点是减少冗余的错误和复杂性,而不是节省空间。)

如果您不想重复字符串以实现(依赖)原因(以更多连接为代价占用空间或操作速度),则添加名称ID和字符串的表并按id列和值替换旧名称列和值。 (这不是规范化,为了依赖于实现的数据优化权衡,这会使您的模式复杂化。并且您应该演示这是必需的并且有效。)

答案 1 :(得分:1)

当建模多对多关系时,正如Kleskowy在评论中所述,每个关系(模型&lt; - &gt;颜色)在连接表中需要一个条目。

您可以通过以下方式重现您的示例:

CREATE TABLE car_model(car_model_id serial NOT NULL PRIMARY KEY, model_name text NOT NULL);
CREATE TABLE car_color(car_color_id serial NOT NULL PRIMARY KEY, color_name text NOT NULL);
CREATE TABLE join_model_color(
  car_model_id int NOT NULL REFERENCES car_model(car_model_id),
  car_color_id int NOT NULL REFERENCES car_color(car_color_id),
  CONSTRAINT model_color_unique_entries UNIQUE(car_model_id, car_color_id)
);

然后插入您的数据:

INSERT INTO car_model(model_name) SELECT 'Volvo V70' UNION SELECT 'Volvo V60';
INSERT INTO car_color(color_name) SELECT 'Pearl White' UNION SELECT 'Emerald Green' UNION SELECT 'Night Black' UNION SELECT 'Salmon Pink' UNION SELECT 'Ocean Blue' UNION SELECT 'Raspberry Red';
INSERT INTO join_model_color SELECT car_model_id, car_color_id FROM car_model, car_color WHERE model_name = 'Volvo V70' AND color_name IN ('Pearl White', 'Emerald Green', 'Night Black', 'Salmon Pink', 'Ocean Blue', 'Raspberry Red');
INSERT INTO join_model_color SELECT car_model_id, car_color_id FROM car_model, car_color WHERE model_name = 'Volvo V60' AND color_name IN ('Pearl White', 'Emerald Green', 'Night Black', 'Salmon Pink', 'Ocean Blue', 'Raspberry Red');

然后您可以查询您的数据,例如:

SELECT color_name FROM car_model NATURAL INNER JOIN join_model_color NATURAL INNER JOIN car_color WHERE model_name = 'Volvo V70';
SELECT model_name FROM car_model NATURAL INNER JOIN join_model_color NATURAL INNER JOIN car_color WHERE color_name = 'Emerald Green';