我正在尝试规范化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;
答案 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。