Postgresql - 找出INET范围内的第一个缺口

时间:2018-04-20 13:47:43

标签: sql postgresql

我有以下用于存储IP的表结构(PostgreSQL):

CREATE TABLE ips (
  ip INET NOT NULL
);

INSERT INTO ips VALUES ('127.0.0.1');
INSERT INTO ips VALUES ('127.0.0.5');
INSERT INTO ips VALUES ('127.0.0.6');

如何找到127.0.0.2,因为它是下一个免费的最低IP?

我有点坚持如何以优化的方式解决这个问题。

这似乎是这样做的,但是一种减慢子网大小/ 10(4M +记录)的方法:

SELECT sub.ip FROM
(SELECT set_masklen(((generate_series(1, (2 ^ (32 - masklen('127.0.0.0/10'::cidr)))::integer - 2) + '127.0.0.0/10'::cidr)::inet), 32) as ip) AS sub
WHERE sub.ip NOT IN
(SELECT ip from ips)
AND sub.ip > set_masklen('127.0.0.0/10', 32)
AND sub.ip < set_masklen(broadcast('127.0.0.0/10')::inet, 32)
ORDER BY ip ASC LIMIT 1;

2 个答案:

答案 0 :(得分:1)

您可以使用inet功能:

select ips.ip + 1
from ips
where not exists (select 1 from ips ips2 where ips2.ip = ips.ip + 1)
order by ips.ip
limit 1;

答案 1 :(得分:0)

如果使用9.3或更高版本,则可以利用横向连接。

SELECT (a.ip+1) as low, q.ip as high FROM ips a LEFT JOIN LATERAL
 (SELECT * FROM ips b WHERE a.ip < b.ip ORDER BY b.ip ASC limit 1) AS q ON true
 WHERE q.ip <> (a.ip + 1) LIMIT 1;

使用正确的过滤器和排序加入同一个表,然后使用ip + 1生成每行的下一个数字并检查它是否匹配。将结果限制在第一个。