GROUP BY 没有按预期工作
GROUP BY isn't working as expected
这是我的样本 table,只有一点信息。
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
我想做的是从路由器列中识别出只有 part_name 条目以 MPC 开头的元素。我想出的是这个,但它是错误的,因为它列出了上面的两个元素。
SELECT router
FROM juniper_fpc
WHERE part_name LIKE 'MPC%'
GROUP BY router
ORDER BY router;
router
-----------
AAAA-ZZZ1
BBBB-ZZZ1
如果您的意思是 select 只有那些路由器,它们的所有部件名称都以 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;
假设您想要只有 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(*)
这应该表现良好:
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;
和 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;
详情:
- Select rows which are not present in other table
或者, 使用 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)
上建立索引。
你也可以 Window 这里的功能:
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
如果此查询范围扩大,这将为更复杂的条件打开大门。
这是我的样本 table,只有一点信息。
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
我想做的是从路由器列中识别出只有 part_name 条目以 MPC 开头的元素。我想出的是这个,但它是错误的,因为它列出了上面的两个元素。
SELECT router
FROM juniper_fpc
WHERE part_name LIKE 'MPC%'
GROUP BY router
ORDER BY router;
router
-----------
AAAA-ZZZ1
BBBB-ZZZ1
如果您的意思是 select 只有那些路由器,它们的所有部件名称都以 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;
假设您想要只有 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(*)
这应该表现良好:
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;
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;
详情:
- Select rows which are not present in other table
或者,
SELECT router
FROM juniper_fpc
GROUP BY router
HAVING count(*) = count(*) FILTER (WHERE part_name LIKE 'MPC%')
ORDER BY router;
最好为每个人在 (router, partname)
上建立索引。
你也可以 Window 这里的功能:
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
如果此查询范围扩大,这将为更复杂的条件打开大门。