我有一个数据库(MySQL 5.1),它使用交叉引用表(下例中的local_ref)来获取值的数字ID。我已经介绍了另一个交叉引用表(foreign_ref,下面),以将这些数字ID引用到另一个数据库中的索引。通常这不是一个复杂的连接,但是,我有多个列使用交叉引用表中的键(val1和val2,下面)。
E.g:
mysql> select * from foo;
+-----+------+------+
| id | val1 | val2 |
+-----+------+------+
| 100 | A | B |
| 200 | A | D |
| 300 | B | C |
+-----+------+------+
mysql> select * from local_ref;
+----+-------+
| id | value |
+----+-------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
| 5 | E |
+----+-------+
mysql> select * from foreign_ref;
+----------+------------+
| local_id | foreign_id |
+----------+------------+
| 1 | 10 |
| 2 | 20 |
| 3 | 30 |
| 4 | 40 |
+----------+------------+
我需要的是以下内容:
+-----+---------+---------+
| id | val1_id | val2_id |
+-----+---------+---------+
| 100 | 10 | 20 |
| 200 | 10 | 40 |
| 300 | 20 | 30 |
+-----+---------+---------+
知道原始表没有按原样进行规范化,我通过以下两种方式实现了结果:
将两个交叉引用表混淆两次:
SELECT
FOO.id, F_R1.foreign_id, F_R2.foreign_id
FROM FOO
JOIN
Local_Ref as L_R1 ON (FOO.val1 = L_R1.value)
JOIN
Local_Ref as L_R2 ON (FOO.val2 = L_R2.value)
JOIN
Foreign_Ref as F_R1 ON (L_R1.id = F_R1.local_id)
JOIN
Foreign_Ref as F_R2 ON (L_R2.id = F_R2.local_id)
两次连接交叉引用表并为每个连接设置别名。
SELECT
FOO.id, joint1.foreign_id, joint2.foreign_id
FROM
FOO
JOIN
(
SELECT * FROM Local_Ref JOIN Foreign_Ref ON Local_Ref.id = Foreign_Ref.local_id
) as joint1
ON FOO.val1 = joint1.value
JOIN
(
SELECT * FROM Local_Ref JOIN Foreign_Ref ON Local_Ref.id = Foreign_Ref.local_id
) as joint2
ON FOO.val2 = joint2.value
我觉得这两种方法效率都很低,可以改进。除了重建数据库,还有更有效的解决方案吗?
答案 0 :(得分:0)
如果无法重构foo
表,那么获得结果的另一种方法是取消忽略该表中的数据。
MySQL没有unpivot功能,但您使用了UNION ALL查询。
基本语法为:
select id, 'val1' col, val1 value
from foo
union all
select id, 'val2' col, val2 value
from foo
请参阅Demo
这将把具有多列的去规范化表转换为多行,这样更容易加入。一旦数据采用这种格式,那么您可以连接到其他表一次,而不是两次。最后,您可以应用带有CASE表达式的聚合函数将值转换为列:
select f.id,
max(case when f.col = 'val1' then fr.foreign_id end) val1_id,
max(case when f.col = 'val2' then fr.foreign_id end) val2_id
from
(
select id, 'val1' col, val1 value
from foo
union all
select id, 'val2' col, val2 value
from foo
) f
inner join local_ref l
on f.value = l.value
inner join foreign_ref fr
on l.id = fr.local_id
group by f.id
见SQL Fiddle with Demo。这给出了一个结果:
| ID | VAL1_ID | VAL2_ID |
---------------------------
| 100 | 10 | 20 |
| 200 | 10 | 40 |
| 300 | 20 | 30 |