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

我觉得这两种方法都非常低效,可以改进。除了重建数据库,还有没有更高效的解决方案?

4

1 回答 1

0

如果您无法重组foo表,那么获得结果的另一种方法是取消透视该表中的数据。

MySQL 没有 unpivot 函数,但您使用了 UNION ALL 查询。

基本语法将是:

select id, 'val1' col, val1 value
from foo
union all
select id, 'val2' col, val2 value
from foo

演示

这会将具有多列的非规范化表转换为更容易加入的多行。一旦数据采用这种格式,您就可以连接到其他表一次,而不是两次。最后,您可以应用带有 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 |
于 2013-05-29T21:42:51.627 回答