Это работает для меня на 8.3 - должно быть хорошо и на 8.4.Нам нужен пользовательский агрегат, потому что max(cidr)
не является встроенным (даже если >
есть)
create or replace function greatest_pair(cidr, cidr)
returns cidr
language 'sql' immutable as
$$select greatest($1, $2);$$;
create aggregate max( basetype = cidr,
sfunc = greatest_pair,
stype = cidr );
select max_nb, count(*)
from ( select ip, max(nb) as max_nb
from netblocks n join iplog i on(i.ip << n.nb)
group by ip ) z
group by max_nb;
max_nb | count
----------------+-------
192.168.1.0/24 | 2
10.0.0.0/8 | 1
192.168.0.0/16 | 1
Если вам не нужен пользовательский агрегат, вы можете сделать:
create or replace view v as
select ip, nb from netblocks n join iplog i on(i.ip << n.nb);
select nb, count(*)
from ( select *
from v o
where not exists ( select *
from v i
where i.ip=o.ip and i.nb>o.nb ) ) z
group by nb;
или аналогичное с использованием предложения with
и отсутствием представления в 8.4, но в ответе на вопрос эффективно : -)
протестировано с этими представлениями:
create or replace view iplog as
select '192.168.1.100'::inet as ip union all
select '192.168.1.101'::inet union all
select '192.168.55.5'::inet union all
select '10.1.2.3'::inet;
create or replace view netblocks as
select '192.168.1.0/24'::cidr as nb union all
select '192.168.0.0/16'::cidr union all
select '10.0.0.0/8'::cidr union all
select '0.0.0.0/0'::cidr;