以连接计数

时间:2016-03-17 13:16:09

标签: sql database postgresql join left-join

我在contactproject之间有多对多关联。

contact:
+-----------------+--------------+------+-----+---------+----------------+
| Field           | Type         | Null | Key | Default | Extra          |
+-----------------+--------------+------+-----+---------+----------------+
| id              | int(11)      | NO   | PRI | NULL    | auto_increment |
| deleted         | boolean      | NO   |     | NULL    |                |
+-----------------+--------------+------+-----+---------+----------------+

project:
+-----------------+--------------+------+-----+---------+----------------+
| Field           | Type         | Null | Key | Default | Extra          |
+-----------------+--------------+------+-----+---------+----------------+
| id              | int(11)      | NO   | PRI | NULL    | auto_increment |
| status          | varchar      | NO   |     | NULL    |                |
+-----------------+--------------+------+-----+---------+----------------+

project_contact:
+---------------+---------+------+-----+---------+-------+
| Field         | Type    | Null | Key | Default | Extra |
+---------------+---------+------+-----+---------+-------+
| project_id    | int(11) | NO   | PRI | NULL    |       |
| contact_id    | int(11) | NO   | PRI | NULL    |       |
| proj_con_role | varchar | NO   |     | NULL    |       |
+---------------+---------+------+-----+---------+-------+

我想知道有多少联系人与没有项目,一个项目或多个项目相关联。但是,对于那些后者(一个项目和一个以上的项目),项目状态必须是'STATUS_X'. proj_con_role必须是'CLIENT'而且,联系人不得标记为删除。如果我可以在一个查询中得到它,那绝对是非常棒的,如果没有,3个不同的查询也可以。

到目前为止,我有这个:

SELECT   numprojects,
         Count(*) AS numcontacts
FROM     (
                   SELECT    c.id,
                             Count(pc.contact_id) AS numprojects
                   FROM      contact c
                   LEFT JOIN project_contact pc
                   ON        pc.contact_id = c.id
                   AND       pc.proj_con_role = 'CLIENT'
                   WHERE     (
                                       c.deleted isnull
                             OR        c.deleted = false)
                   GROUP BY  c.id ) c
GROUP BY numprojects
ORDER BY numprojects

现在,这很好用,但对于我的生活,我似乎无法添加项目必须具有某种状态的条件......我不知道如何添加它。任何帮助都会非常棒。

我尝试过添加:

left join project p on p.status = 'STATUS_X' and p.id = pc.project_id

但当然,它不会像这样工作......

稍后编辑1:

如果我添加:

inner join project p on p.status = 'STATUS_X' and p.id = pc.project_id

我为一个或多个项目获得了正确的结果,但没有项目的联系人被忽略。也许在这里结合?不确定。

3 个答案:

答案 0 :(得分:0)

这应该有效:

select
case when project_contracts = 0 then '0 projects'
when project_contracts = 1 then '1 project'
else '2+ projects' end as num_of_projects
count(contracts) as contracts
from
    (select 
    c.id as contracts
    sum(case when p.id is null then 0 else 1 end) as projects_contracts
    from contracts c
    left join project_contracts p on p.id = c.id
    group by c.id)
group by case when project_contracts = 0 then '0 projects'
when project_contracts = 1 then '1 project'
else '2+ projects' end

答案 1 :(得分:0)

列出合约无合约的合约(无合约)

                   SELECT    *
                   FROM      contact c
                   LEFT JOIN project_contact pc  --Left join = all contacts, even if no join to a contract is made
                   ON        pc.contact_id = c.id
                   AND       pc.proj_con_role = 'CLIENT'
                   WHERE     (c.deleted isnull
                             OR c.deleted = false) 
                             AND pc.id isnull  --Clients with no contacts

对于有合同的联系人

                   SELECT    *
                   FROM      contact c
                   INNER JOIN project_contact pc  --Inner join only shows succesful joins (meaning neither ID can be null)
                   ON        pc.contact_id = c.id
                   AND       pc.proj_con_role = 'CLIENT'
                   WHERE     (c.deleted isnull
                             OR c.deleted = false) 
                             AND pc.status = 'Status_X' --your status

我无法测试代码,但你需要的是Left Join for null contract和Inner join来查找所有匹配项,然后根据状态进行过滤。

我列出的两个代码只选择记录/连接,因此您必须以您需要的任何方式使用结果(计数,我假设)。

答案 2 :(得分:0)

我这样解决了:

SELECT   numprojects,
         Count(*) AS numcontacts
FROM     (
                    SELECT     c.id,
                               Count(pc.contact_id) AS numprojects
                    FROM       contact c
                    LEFT JOIN  project_contact pc
                    ON         pc.contact_id = c.id
                    AND        pc.proj_con_role = 'CLIENT'
                    INNER JOIN project p
                    ON         p.status = 'STATUS_X'
                    AND        p.id = pc.mandate_id
                    WHERE      (
                                          c.deleted isnull
                               OR         c.deleted = false)
                    GROUP BY   c.id ) c
GROUP BY numprojects
UNION ALL
SELECT   numprojects,
         count(*) AS numcontacts
FROM     (
                   SELECT    c.id,
                             count(pc.contact_id) AS numprojects
                   FROM      contact c
                   LEFT JOIN project_contact pc
                   ON        pc.contact_id = c.id
                   AND       pc.project_contact_role = 'CLIENT'
                   WHERE     (
                                       c.deleted isnull
                             OR        c.deleted = false)
                   GROUP BY  c.id ) c
WHERE    numprojects = 0
GROUP BY numprojects
ORDER BY numprojects

谢谢大家的回答和支持。