三个表连接,其中中间表有重复的外键

时间:2015-04-15 21:15:14

标签: sql oracle join

我正在使用一个数据库,其结构类似于下图(除了更多列)。基本上,每个人都有一个唯一的person_id和alt_id。但是,将表A连接到表C的唯一事情是表B,而表B对于每个人/ alt_id都有一对多行。

我需要获取包含person_id,alt标识及其相关形状的行。

我可以这样做:

SELECT DISTINCT a.person_id, a.color, b.alt_id, c.shape 
 FROM a 
 JOIN b ON a.person_id = b.person_id
 JOIN c ON b.alt_id = c.alt_id

然而,这似乎效率低下,因为在最终使用DISTINCT缩小结果之前,它将采用具有相同alt_id的B和C行的笛卡尔积。什么是进行此查询的最佳/最有效的方式?

Table A

+-----------+-------+
| person_id | color |
+-----------+-------+
|        10 | red   |
|        11 | blue  |
|        12 | green |
+-----------+-------+

Table B
+-----------+--------+
| person_id | alt_id |
+-----------+--------+
|        10 |    225 |
|        10 |    225 |
|        11 |    226 |
|        11 |    226 |
|        11 |    226 |
|        12 |    227 |
+-----------+--------+

Table C
+--------+----------+
| alt_id |  shape   |
+--------+----------+
|    225 | square   |
|    226 | circle   |
|    226 | rhombus  |
|    226 | ellipse  |
|    227 | triangle |
+--------+----------+

3 个答案:

答案 0 :(得分:1)

加入(select distinct * from b) b,而不仅仅是基本表b

SELECT
    a.person_id, a.color, b.alt_id, c.shape 
FROM
    a
    INNER JOIN (select distinct * from b) b
        ON a.person_id = b.person_id
    INNER JOIN c
        ON b.alt_id = c.alt_id

答案 1 :(得分:1)

在进行连接之前,您可以从b获取不同的值列表。

SELECT DISTINCT a.person_id, a.color, b.alt_id, c.shape 
FROM a 
JOIN (Select Distinct person_id, alt_id from b) b ON a.person_id = b.person_id
JOIN c ON b.alt_id = c.alt_id

请注意,由于索引和统计信息,获取DISTINCT列表并不总是一个好主意。查看实际执行计划以评估其有多好,特别是如果您有大量数据。

答案 2 :(得分:1)

您可以使用聚合以及公用表表达式(或子查询,但CTE可能更整洁):

WITH ab AS (
    SELECT a.person_id, a.color, MAX(b.alt_id) AS alt_id
      FROM a INNER JOIN b
        ON a.person_id = b.person_id
     GROUP BY a.person_id, a.color
)
SELECT ab.person_id, ab.color, ab.alt_id, c.shape
  FROM ab INNER JOIN c ON ab.alt_id = c.alt_id;