计算每个最小网络块的记录数(间隔)
在 SQL (postgresql 8.4.x) 中,如何有效地COUNT
落入可能包含网络块的最小网络块内的 IP 记录数量?例如,我不想将 10.0.0.1
计入 10/8
和 0/0
下。
更具体地说,给出:
-- 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
In SQL (postgresql 8.4.x), how can I efficiently COUNT
the number of IP records falling within the smallest netblock of possibly encompassing netblocks? I don't want to count 10.0.0.1
under both 10/8
and 0/0
, for example.
More concretely, given:
-- 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 | ...
How can I efficiently produce the result set:
nb | ips_logged
===============+============
192.168.1.0/24 | 2
192.168.0.0/16 | 1
10.0.0.0/8 | 1
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这对我在 8.3 上有效 - 在 8.4 上也应该没问题。我们需要一个自定义聚合,因为
max(cidr)
不是内置的(即使>
是)如果您不想要自定义聚合,您可以这样做:
或类似的使用
with
子句,并且在 8.4 上没有视图,但问题说有效 :-)使用这些视图进行测试:
This works for me on 8.3 - it should be fine on 8.4 as well. We need a custom aggregate because
max(cidr)
is not built-in (even though>
is)If you don't want the custom aggregate, you can do:
or similar using a
with
clause and no view on 8.4, but the question said efficiently :-)tested with these views:
由于 IPv4 地址本质上是 4 个字节,因此它们可以表示为整数。您可以制作一个包含 netblock_start 和 netblock_end 的表(例如 192.168.1.0/24 将是 192.168.1.0 到 192.168.1.255,分别是 3232235776 到 3232235776),然后计算
ip >= netblock_start && ip <= netblock_end
(日志中的 IP 需要转换为相同的格式才能正常工作)。Since IPv4 addresses are essentially 4 bytes, they can be represented as an integer. You can make a table containing netblock_start and netblock_end (so e.g. 192.168.1.0/24 would be 192.168.1.0 to 192.168.1.255, resp. 3232235776 to 3232235776), then count
ip >= netblock_start && ip <= netblock_end
(the IP from your log needs to be converted into the same format for this to work).@JackPDouglas的答案非常出色。为了完整起见,这是我突然想到的天真的方法:
@JackPDouglas' answer is superior. For completeness, this is the naive approach I came up with off the top of my head: