sql - 计算每个最小网络 block 的记录(间隔)

标签 sql postgresql count intervals

在 SQL (postgresql 8.4.x) 中,我如何有效地COUNT IP 记录的数量落入可能的最小 netblock包括网 block ?例如,我不想在 10/80/0 下计算 10.0.0.1

更具体地说,给定:

-- CREATE TABLE iplog (ip INET NOT NULL, ...)
--
      ip      | ...
==============+=====
192.168.1.100 | ...
192.168.1.101 | ...
192.168.55.5  | ...
10.1.2.3      | ...

-- CREATE TABLE netblocks (nb CIDR UNIQUE NOT NULL, ...)
--
       nb      | ...
===============+======
192.168.1.0/24 | ...
192.168.0.0/16 | ...
10.0.0.0/8     | ...
0.0.0.0/0      | ...

如何高效地生成结果集:

       nb      | ips_logged
===============+============
192.168.1.0/24 | 2
192.168.0.0/16 | 1
10.0.0.0/8     | 1

最佳答案

这对我适用于 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 上没有 View ,但问题是有效地 :-)

使用这些 View 进行测试:

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;

关于sql - 计算每个最小网络 block 的记录(间隔),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4378123/

相关文章:

sql - 如何在我的选择查询中使用动态变量 @counter 作为 TOP 值

sql - 为什么在 postgresql 中表称为关系?

php - 命令不同步;你现在不能运行这个命令

sql - 从状态变化历史记录中获取每天的用户状态

javascript - Sequelize 计数关联条目与单独的

javascript - 如何显示从 *ngFor Loop Angular 6 生成的相似结果的计数?

Javascript构造函数来计算实例数

sql - 连通分量

database - Postgres order by foreign key 性能?

r - 如何在 r 中的第一个观察值和前两个连续的负值观察值之间找到观察值的数量