4

我需要按子网(前 3 个八位字节)对 IP 列表进行分组来计算它。例如,如果我有 Ips

123.12.12.12
123.12.12.11
123.12.11.11

我必须得到这样的结果:

123.12.12 | 2
123.12.11 | 1

我用谷歌搜索了这个例子:

select 
substr(ip,1,locate('.',ip,locate('.',ip)+1)-1) 
as ip, count(ip) as count
from ip_list
group by ip ORDER BY count  DESC

但它仅按前两个八位位组对列表进行分组。我迷失在这一切中locate(locate(locate(...)))。有人可以帮助修改它以获得正确的结果吗?

4

4 回答 4

8

您应该使用group by 表达式 name

select 
--   locate( '.', ip, locate( '.', ip, locate( '.', ip ) + 1 ) + 1 ) as l,
   substr( ip, 1, locate( '.', ip
                          , locate( '.', ip
                                    , locate( '.', ip ) + 1 ) + 1 ) - 1 ) as subip,
   count(ip) as count
from ip_list
group by ( subip )
order by count desc
;

编辑1:不需要使用
。可用于过滤 IP 的子集。locateSUBSTR_INDEX

示例

select
       substring_index( ip, '.', 3 ) as subip
     , count(ip) as count
  from ip_list
 group by ( subip )
 order by count desc

请参阅文档

于 2012-06-03T11:45:53.697 回答
1

使用这种逻辑,恐怕您将需要另一层locate

substr(ip, 1, locate('.', ip, locate('.', ip, locate('.', ip)+1) +1) - 1)
于 2012-06-03T11:42:05.173 回答
1

你可以使用

GROUP BY INET_ATON(ip)/256
于 2012-06-03T11:49:39.057 回答
0

如果你制作一个 IP 二进制文件,你可以在它上面应用一个掩码,它只保留你 IP 地址的前 3 部分。面具看起来像这样:

11111111111111111111111100000000

所以,作为一个数字,它看起来像:

SELECT CONV('11111111111111111111111100000000' ,2,10) as mask;
-- Result: 4294967040

如果您使用此掩码对您的 IP 地址进行按位与运算,您将得到如下结果:

SELECT
'1.0.207.199',                
INET_NTOA( INET_ATON( '1.0.207.199') & 4294967040 ) ;
-- Result:
-- 1.0.207.199
-- 1.0.207.0

INET_ATON 将 ip (A)daddress (TO) 转换为 (N) 数字,而 INET_NTOA 反之亦然(虽然真正的含义代表 ASCII TO Network,但我更喜欢这个 shofthand ;-)。

因此,您可以像这样按 IP 地址分组:

SELECT
    INET_NTOA( INET_ATON( ip ) & 4294967040 ) AS ipgroup, 
    COUNT(ip) AS count
FROM ip_list
GROUP BY ipgroup 
ORDER BY count DESC;

我希望它有所帮助。

于 2017-05-26T14:37:36.343 回答