如何计算 table 中的对象数量,按 has_many 中的列分组,某些条件是否重要?
How to count number of objects in table, grouped by column in has_many, for which some conditions matter?
我有一个叫 cars (id, brand)
的 table。汽车可以有很多 adverts (id, car_id, state, dealer_name)
.
我想计算 独特 汽车的数量,以 dealer_name
为一组,该特定经销商是目前唯一拥有汽车的经销商 for sale
https://www.db-fiddle.com/f/cjstvXSZ2sWYNqfe6LRcTc/1(查询的预期输出也写在那里)
我已经设法在 ruby 应用程序中以迭代方式执行此操作,为每个 dealer_name
执行一个查询,但是我无法在单个分组查询中执行此操作。
数据:
cars
id make
1 'BMW'
2 'Mercedes'
3 'Mercedes'
4 'Volvo'
5 'Volvo'
6 'Volvo'
7 'Alfa Romeo'
adverts
id car_id state dealer_name
1 1 'sold' 'Dealer 1'
2 2 'for sale' 'Dealer 1'
4 3 'for sale' 'Dealer 2'
5 4 'for sale' 'Dealer 2'
6 5 'for sale' 'Dealer 3'
7 5 'for sale' 'Dealer 4'
8 7 'sold' 'Dealer 4'
expected output:
dealer_name Number of cars with only this dealer having the car currently 'for sale'
Dealer 1 1
Dealer 2 2
Dealer 3 0
Dealer 4 0
您可以在子查询中进行 window 计数,然后在外部查询中使用条件聚合:
select
dealer_name,
sum(case when cnt = 1 and state = 'for sale' then 1 else 0 end) cnt
from (
select
dealer_name,
state,
car_id,
count(*) over(partition by car_id, state) cnt
from adverts a
) x
group by dealer_name
order by dealer_name;
| dealer_name | cnt |
| ----------- | --- |
| Dealer 1 | 1 |
| Dealer 2 | 2 |
| Dealer 3 | 0 |
| Dealer 4 | 0 |
注意:这是一个有据可查的问题,SO 可以使用更多!
如果您可以为同一笔交易拥有重复的汽车(有点暗示您希望计算不同的汽车),那么这就比较棘手了。 Postgres 不支持 count(distinct)
作为聚合函数。
一种方法是:
select dealer_name,
count(distinct car_id) filter (where state = 'for sale' and min_dn = max_dn) as cnt
from (select a.*,
min(a.dealer_name) over (partition by a.car_id, a.state) as min_dn,
max(a.dealer_name) over (partition by a.car_id, a.state) as max_dn
from adverts a
) a
group by dealer_name
order by dealer_name;
或者您可以使用两级聚合:
select dealer_name,
count(*) filter (where for_sale and num_dealers = 1) as cnt
from (select dealer_name, car_id,
bool_or(state = 'for sale') as for_sale,
count(*) filter (where state = 'for sale' over (partition by car_id)) as num_dealers
from adverts
group by dealer_name, car_id
) dc
group by dealer_name;
这些也是 return 所有 经销商,即使他们没有汽车出售。
我有一个叫 cars (id, brand)
的 table。汽车可以有很多 adverts (id, car_id, state, dealer_name)
.
我想计算 独特 汽车的数量,以 dealer_name
为一组,该特定经销商是目前唯一拥有汽车的经销商 for sale
https://www.db-fiddle.com/f/cjstvXSZ2sWYNqfe6LRcTc/1(查询的预期输出也写在那里)
我已经设法在 ruby 应用程序中以迭代方式执行此操作,为每个 dealer_name
执行一个查询,但是我无法在单个分组查询中执行此操作。
数据:
cars
id make
1 'BMW'
2 'Mercedes'
3 'Mercedes'
4 'Volvo'
5 'Volvo'
6 'Volvo'
7 'Alfa Romeo'
adverts
id car_id state dealer_name
1 1 'sold' 'Dealer 1'
2 2 'for sale' 'Dealer 1'
4 3 'for sale' 'Dealer 2'
5 4 'for sale' 'Dealer 2'
6 5 'for sale' 'Dealer 3'
7 5 'for sale' 'Dealer 4'
8 7 'sold' 'Dealer 4'
expected output:
dealer_name Number of cars with only this dealer having the car currently 'for sale'
Dealer 1 1
Dealer 2 2
Dealer 3 0
Dealer 4 0
您可以在子查询中进行 window 计数,然后在外部查询中使用条件聚合:
select
dealer_name,
sum(case when cnt = 1 and state = 'for sale' then 1 else 0 end) cnt
from (
select
dealer_name,
state,
car_id,
count(*) over(partition by car_id, state) cnt
from adverts a
) x
group by dealer_name
order by dealer_name;
| dealer_name | cnt |
| ----------- | --- |
| Dealer 1 | 1 |
| Dealer 2 | 2 |
| Dealer 3 | 0 |
| Dealer 4 | 0 |
注意:这是一个有据可查的问题,SO 可以使用更多!
如果您可以为同一笔交易拥有重复的汽车(有点暗示您希望计算不同的汽车),那么这就比较棘手了。 Postgres 不支持 count(distinct)
作为聚合函数。
一种方法是:
select dealer_name,
count(distinct car_id) filter (where state = 'for sale' and min_dn = max_dn) as cnt
from (select a.*,
min(a.dealer_name) over (partition by a.car_id, a.state) as min_dn,
max(a.dealer_name) over (partition by a.car_id, a.state) as max_dn
from adverts a
) a
group by dealer_name
order by dealer_name;
或者您可以使用两级聚合:
select dealer_name,
count(*) filter (where for_sale and num_dealers = 1) as cnt
from (select dealer_name, car_id,
bool_or(state = 'for sale') as for_sale,
count(*) filter (where state = 'for sale' over (partition by car_id)) as num_dealers
from adverts
group by dealer_name, car_id
) dc
group by dealer_name;
这些也是 return 所有 经销商,即使他们没有汽车出售。