项目需求:需要根据区域IP筛选出在此区间的IP地址。
例如:192.168.1.1~192.168.1.20,就需要获取到在这个区间里的所有IP
一、MySQL版本
- 5.7.27-log
select version(); -- MySQL版本查看
二、问题分析
1、建表语句
CREATE TABLE `testip` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ip` varchar(32) DEFAULT NULL,
`ip_value` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
insert into `testip`(`id`,`ip`,`ip_value`) values
(1,'192.168.1.1',3232235777),
(2,'192.168.1.2',3232235778),
(3,'192.168.1.3',3232235779),
(4,'192.168.1.4',3232235780),
(5,'192.168.1.5',3232235781),
(6,'192.168.1.12',3232235788),
(7,'192.168.1.20',3232235796),
(8,'192.168.1.30',3232235806);
2、数据查询示例
- 首先想到的就是通过字符串的比较来获取查找结果,执行结果发现数据有误。
SELECT * FROM testip WHERE ip BETWEEN '192.168.1.1' AND '192.168.1.25'
SQL执行结果如下,与期望结果不符:
SELECT * FROM testip WHERE ip BETWEEN '192.168.1.3' AND '192.168.1.25'
SQL执行结果,出现了空集的情况:
- 发现MySQL字符串比较是一个字符一个字符的比较,当对应字符相同时,就比较下一个,直到遇到能区分大小的字符,才停止比较,后面的字符也将忽略。
- 例如:查询在
192.168.1.4
到192.168.1.20
之间的 IP 地址,如果通过字符串查询就会出现空集的情况,因为192.168.1.4
已经大于192.168.1.20
了,所以需要把IP转换成对应数字来进行比较。
网络地址每一个值最大不会超过255,255对应的十六进制值就是ff:
ip | 十六进制 | 二进制 | 十进制 |
---|---|---|---|
255.255.255.255 | ff ff ff ff | 11111111 11111111 11111111 11111111 | 4294967295 |
192.168.1.168 | c0 a8 1 a8 | 11000000 10101000 00000001 10101000 | 3232235944 |
三、INET_ATON()函数说明
- INET_ATON():将ip地址转换成数字:
select INET_ATON('192.168.1.168')
- 结果
四、INET_NTOA()函数说明
- INET_NTOA():将数字转换成IP地址:
select INET_NTOA('3232235944')
- 结果:
五、问题解决
获取正确的结果:
-- 3232235777 -> 192.168.1.1, 3232235796 -> 192.168.1.20
SELECT * FROM testip WHERE ip_value BETWEEN 3232235777 AND 3232235796
SQL执行结果:
-- 3232235779 -> 192.168.1.3, 3232235801 -> 192.168.1.25
SELECT * FROM testip WHERE ip_value BETWEEN 3232235779 AND 3232235801
SQL执行结果: