2013-05-29 73 views
0

我有一个数据库(MySQL 5.1),它使用交叉引用表(local_ref,在下面的示例中)获取值的数字ID。我已经引入了另一个交叉引用表(下面的foreign_ref)来将这些数字ID引用到另一个数据库中的索引。通常情况下,这不是一个复杂的连接,但是,我有多个使用交叉引用表(下面的val1和val2)中的键的列。基于两个交叉引用表连接多个表

如:

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表,那么另一种获得结果的方式是unpivot该表中的数据。

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 | 
+0

感谢您的详细回复。我现在最终使用了别名,但我可能最终会在将来使用它。 – Kyle