使用MySQL中的三个表填充多对多人物颜色表

时间:2016-11-22 13:18:16

标签: mysql many-to-many relational-database database-normalization

我正在尝试规范化MySQL中的表,将具有许多相似列的表转换为具有两列的多对多关系。我有以下表格:

人:

+----+------+
| id | name |
+----+------+
| 1  | John |
| 2  | Anna |
| 3  | Leon |
+----+------+

person_temp:

+------+--------+--------+--------+--------+
| name | color1 | color2 | color3 | color4 |
+------+--------+--------+--------+--------+
| John |  red   |  blue  |  green |        |
| Anna |  green | yellow |        |        |
| Leon |  blue  |  red   |        |        |
+------+--------+--------+--------+--------+

颜色

+----+--------+
| id |  name  |
+----+--------+
| 1  | red    |
| 2  | blue   |
| 3  | green  |
| 4  | yellow |
+----+--------+

我想在填充多对多关系表之后删除person_temp,如下所示:

人色:

+-----------+----------+
| person_id | color_id |
+-----------+----------+
|     1     |    1     |
|     1     |    2     |
|     1     |    3     |
|     2     |    3     |
|     2     |    4     |
|     3     |    2     |
|     3     |    1     |
+-----------+----------+

但是,我没有找到任何解决方案。我对人的身份的唯一关系是person_temp中的名字。我知道名字是独一无二的,因此将它们用于查询不会有问题。

我尝试使用此SQL,但它无法正常工作,因为person_temp没有id列。

INSERT INTO `person_color`
SELECT p.id, c.id
FROM (
  SELECT id, color1 color
  FROM person_temp
  UNION
    SELECT id, color2 FROM person_temp
  UNION
    SELECT id, color3 FROM person_temp
  UNION
    SELECT id, color4 FROM person_temp
  UNION
    SELECT id, color5 FROM person_temp
) p
  JOIN color c
    ON c.name = p.color;

3 个答案:

答案 0 :(得分:1)

您的原始查询很简单,也很贴心。除了从name选择id而非person_temp之外,您只需要将name与来自id的{​​{1}}一起加入person结束。您不需要单独将所有这些JOIN连接到person_temp

INSERT INTO person_color
SELECT p.id AS person_id, c.id AS color_id
FROM (
     SELECT name, color1 AS color FROM person_temp
  UNION
    SELECT name, color2 FROM person_temp
  UNION
    SELECT name, color3 FROM person_temp
  UNION
    SELECT name, color4 FROM person_temp
  UNION
    SELECT name, color5 FROM person_temp
) nc
JOIN color c
    ON c.name = nc.color
JOIN person p
    ON p.name = nc.name;

表行没有顺序,因此对INSERT中的ORDER BY p.id, c.id没有意义。输出行有一个订单。

PS无论是在提出关系设计还是在更高正常形式的意义上,你都没有正常化。你只是在改进设计。

答案 1 :(得分:0)

感谢@ Viki888我想我已经解决了查询

INSERT INTO `person-color`
SELECT i.id `i.id`, c.id `c.id`
FROM (
  SELECT `p`.`id`, `ptemp`.`color1` `pcolor`
    FROM `person` `p`
      JOIN `person_temp` `ptemp` ON `p`.`name` = `ptemp`.`name`
    UNION
        SELECT `p`.`id`, `ptemp`.`color2` FROM `person` `p`
            JOIN `person_temp` `ptemp` ON `p`.`name` = `ptemp`.`name`
    UNION
        SELECT `p`.`id`, `ptemp`.`color3` FROM `person` `p`
            JOIN `person_temp` `ptemp` ON `p`.`name` = `ptemp`.`name`
    UNION
        SELECT `p`.`id`, `ptemp`.`color4` FROM `person` `p`
            JOIN `person_temp` `ptemp` ON `p`.`name` = `ptemp`.`name`
  ORDER BY `id`
) i
  JOIN color c
    ON c.name = i.pcolor
ORDER BY `i.id`

答案 2 :(得分:0)

对于它的价值,我不会在一次查询中以这种聪明的方式做到这一点。这样做没有任何好处。

编写代码以便在多次传递中执行此操作更简单,更简单意味着您可以更快地完成工作。

INSERT INTO `person-color` (person_id, color_id)
SELECT p.id, c.id
FROM person p 
JOIN person_temp pt ON p.name=pt.name
JOIN color c ON pt.color1=c.name;

INSERT INTO `person-color` (person_id, color_id)
SELECT p.id, c.id
FROM person p 
JOIN person_temp pt ON p.name=pt.name
JOIN color c ON pt.color2=c.name;

INSERT INTO `person-color` (person_id, color_id)
SELECT p.id, c.id
FROM person p 
JOIN person_temp pt ON p.name=pt.name
JOIN color c ON pt.color3=c.name;

INSERT INTO `person-color` (person_id, color_id)
SELECT p.id, c.id
FROM person p 
JOIN person_temp pt ON p.name=pt.name
JOIN color c ON pt.color4=c.name;

不需要使用UNION或ORDER BY。