You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL如何从表条目查询去重的IPv4子网与超网

问题解决方案

你当前使用DISTINCT去重是直接针对主机IP做去重,自然只能返回单个主机地址,PostgreSQL 对inet数据类型提供了原生的网络位操作函数,直接对IP做掩码截断后再去重,就能拿到你需要的聚合子网结果。

固定掩码长度子网提取(满足你当前/24子网需求)

使用set_masklen函数直接将IP地址的主机位清零,指定掩码长度为24即可得到每个IP所属的/24网段,再做去重排序:

SELECT DISTINCT set_masklen(dst_ip, 24) AS dst_subnet
FROM copy_tcp_3
WHERE dst_ip << '10.40.0.0/11' AND vlanid = 11
ORDER BY dst_subnet;

针对你给出的示例数据,上述查询会返回如下结果,完全匹配你要的输出形式:

dst_subnet
-------------
 10.40.3.0/24
 10.41.3.0/24
 10.42.3.0/24
 10.42.20.0/24
 10.42.25.0/24
 10.43.3.0/24

函数说明

set_masklen(inet类型字段, 掩码长度)会直接保留IP对应掩码长度的网络位,将后续主机位全部置0,不需要做字符串切割处理,性能远高于字符串操作,且能完美兼容inet类型的索引。如果后续你需要提取其他掩码长度的网段,比如/16、/22,直接修改第二个参数的掩码数值即可。

使用时注意两个要点:

  • 不要先将inet类型转成字符串再做切割取网段,字符串操作不仅性能差,还容易因为IP格式、补零问题出现计算错误,优先使用inet原生函数。
  • 如果你的查询频次很高,可以给set_masklen(dst_ip, 24)建表达式索引,查询速度会提升数倍。

动态聚合最大超网(可选进阶方案)

如果你不需要固定掩码,而是希望将连续存在的IP自动聚合成尽可能大的超网(比如某/23网段下所有地址都有记录时,自动返回/23网段而不是两个/24网段),在PostgreSQL 14及以上版本可以使用原生的网络聚合函数实现:

SELECT network_agg(dst_ip) AS dst_supernet
FROM copy_tcp_3
WHERE dst_ip << '10.40.0.0/11' AND vlanid = 11;

如果你的PostgreSQL版本低于14,需要通过递归CTE逐段合并相邻网段实现动态聚合,逻辑复杂度较高,日常固定掩码的场景用第一种方案足够。


内容的提问来源于stack exchange,提问作者Farzad Heidari Azad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 23:21:41