MySQL根据条件显示MANY-MANY的关系

时间:2014-05-28 16:47:44

标签: mysql sql join

有两个表:

伙伴

id | name
--------------
1  | partner_1
2  | partner_2
3  | partner_3
4  | partner_4

合同

id | name       | is_active
---------------------------
1  | contract_1 | 1
2  | contract_2 | 0
3  | contract_3 | 1
4  | contract_4 | 0
5  | contract_5 | 0

第三个表格将前两个表格与多对多关系相关联

partner_contract

partner_id | contract_id
------------------------
1          | 1
1          | 2
2          | 3
2          | 2
2          | 4
3          | 5

每个合作伙伴可以有多个合同,其中 ONLY ONE 可以是活动的,有些是非活动的。 合伙人也可能根本没有合同。

我需要一个查询,显示所有合作伙伴以及有效合同。如果合作伙伴没有'有一个有效合同,显示NULL。

partner_id | partner_name | contract_name
-----------------------------------------
1          | partner_1    | contract_1
2          | partner_2    | contract_3
3          | partner_3    | NULL
4          | partner_4    | NULL

我找到了一个解决方案,但在我看来它并不完美。

SELECT
    p.id AS partner_id,
    p.name AS partner_name,
    active_contract.name AS contract_name
FROM partner p
LEFT JOIN (
    SELECT *
    FROM contract c
    LEFT JOIN partner_contract pc on pc.contract_id = c.id
    WHERE c.is_active = 1
) active_contract
ON active_contract.partner_id = p.id

有更优雅的解决方案吗?

1 个答案:

答案 0 :(得分:0)

Ray(已删除)查询接近正确的解决方案。合同上的条件应该是on子句,而不是where子句:

SELECT p.id AS partner_id, p.name AS partner_name, c.name AS contract_name
FROM partner p LEFT JOIN
     partner_contract pc
     ON p.id = pc.partner_id LEFT JOIN
     contract c
     ON pc.contract_id = c.id AND c.is_active = 1;

编辑:

好的,上面的错误。可以使用group by

修复此问题
SELECT p.id AS partner_id, p.name AS partner_name, MAX(c.name) AS contract_name
FROM partner p LEFT JOIN
     partner_contract pc
     ON p.id = pc.partner_id LEFT JOIN
     contract c
     ON pc.contract_id = c.id AND c.is_active = 1
GROUP BY p.id, p.name;

更优雅的解决方案(在我看来):

SELECT p.*,
       (select name
        from partner_contract pc join
             contract c
             on pc.contract_id = c.id AND c.is_active = 1
        where p.id = pc.partner_id
       ) as contract_name
FROM partner p;

SQL Fiddle

这可以利用索引,不需要聚合。