GROUP BY未按预期工作

时间:2016-02-03 15:56:10

标签: sql postgresql aggregate

这是我的样本表,只有一点信息。

select * from juniper_fpc';       
    id     |  router   |     part_name      
-----------+-----------+--------------------
 722830939 | BBBB-ZZZ1 | MPC-3D-16XGE-SFPP 
 722830940 | BBBB-ZZZ1 | MPC-3D-16XGE-SFPP 
 723103163 | AAAA-ZZZ1 | DPCE-R-40GE-SFP   
 723103164 | AAAA-ZZZ1 | MPC-3D-16XGE-SFPP 
 723103172 | AAAA-ZZZ1 | DPCE-R-40GE-SFP   
 722830941 | BBBB-ZZZ1 | MPC-3D-16XGE-SFPP

我要做的是识别路由器列中仅具有以MPC开头的part_name条目的元素。我想出的是这个,但这是错误的,因为它列出了上述两个元素。

SELECT   router
FROM     juniper_fpc
WHERE    part_name LIKE 'MPC%'
GROUP BY router
ORDER BY router;
  router   
-----------
 AAAA-ZZZ1
 BBBB-ZZZ1

4 个答案:

答案 0 :(得分:2)

假设您希望路由器只有part_name,例如' MPC%',您可以使用条件计数:

select * from (
  select router, 
    count(case when part_name like 'MPC%' then 1 else null end) as cnt_mpc,
    count(*) as cnt_overall
  from juniper_fpc  
  group by router) v_inner
where cnt_mpc = cnt_overall

这可以写得更紧凑(尽管可读性稍差)

  select router
  from juniper_fpc  
  group by router
  having count(case when part_name like 'MPC%' then 1 else null end)  = count(*) 

SQL Fiddle

答案 1 :(得分:2)

这应该表现良好:

SELECT j1.router
FROM  (
   SELECT   router
   FROM     juniper_fpc
   WHERE    part_name LIKE 'MPC%'
   GROUP    BY router
   ) j1
LEFT   JOIN juniper_fpc j2 ON j2.router = j1.router
                          AND j2.part_name NOT LIKE 'MPC%'
WHERE  j2.router IS NULL
ORDER  BY j1.router;

@sagi's idea NOT EXISTS,如果你做对了,也会有效:

SELECT router
FROM   juniper_fpc j
WHERE  NOT EXISTS (
   SELECT 1
   FROM   juniper_fpc
   WHERE  router = j.router
   AND    part_name NOT LIKE 'MPC%'
   )
GROUP  BY router
ORDER  BY router; 

详细说明:

SQL Fiddle.

或者@Frank's idea,其语法为Postgres 9.4或更高版本:

SELECT router
FROM   juniper_fpc
GROUP  BY router
HAVING count(*) = count(*) FILTER (WHERE part_name LIKE 'MPC%')
ORDER  BY router;

最适合每个(router, partname)的索引。

答案 2 :(得分:0)

如果你的意思是只选择那些路由器,那么所有的部件名称都以MPC开头,那么你的查询应该是:

SELECT   s.router
FROM     juniper_fpc s
WHERE    NOT EXISTS(select distinct id from juniper_fpc t
                    where t.id = s.id part_name NOT LIKE 'MPC%')
GROUP BY s.router
ORDER BY s.router;

答案 3 :(得分:0)

你也可以在这里使用Window Functions:

SELECT
    *
FROM
    (
        SELECT 
            router,
            part_name,
            COUNT(distinct part_name) OVER (PARTITION BY router) as count_of_distinct_parts
        FROM juniper_fpc
    )subqry
WHERE part_name like 'MPC%' AND count_of_distinct_parts = 1

如果此查询范围扩大,这将为更复杂的条件打开大门。