如何找到2001:48a8::1 to 2001:48a8::ffff
范围内的最小未使用IPv6地址,而不是在使用的ips的特定MySQL表中?
我一直遇到的问题是无法在varbinary(16)
我的整个想法是这样的:
SELECT MIN(IpAddress)+1
FROM IpAddresses t1
WHERE NOT EXISTS (SELECT *
FROM IpAddresses AS t2
WHERE t2.IPAddress = t1.IPAddress+1
AND t2.AddressRangeID = ?)
但这只有在我能用varbinary(16)
进行数学运算时才有效。
答案 0 :(得分:1)
通常使用位掩码检查IP地址范围。
2001:48a8::5 & FFFF:FFFF::0 = 2001:48a8::0 # in range
2002:48a8::5 & FFFF:FFFF::0 == 2002:48a8::0 # out of range
不幸的是,MySQL中的bitwise operators处理二进制类型,它们通过转换为64位大整数而不是IPv6地址所需的128位来实现。
幸运的是,我们可以在VARBINARY数据上使用字符串函数。 LEFT()
执行与位掩码相同的功能。
LEFT(2001:48a8::5, 4) = 200148a8 # in range
LEFT(2002:48a8::5, 4) = 200248a8 # out of range
它是LEFT(x, 4)
而不是LEFT(x, 8)
因为每个十六进制字符代表16位,所以其中两个构成32位字符。
像这样把它们放在一起。
SELECT HEX(IpAddress), HEX(LEFT(IpAddress, 4))
FROM IpAddresses
WHERE LEFT(IpAddress, 4) = UNHEX("200148A8");
您要求范围内的最小IP 不。既然你不能在varbinary上做数学,我建议你只需要在范围内获得最大值并在SQL之外进行数学运算。
SELECT HEX(MAX(IpAddress))
FROM IpAddresses
WHERE LEFT(IpAddress, 4) = UNHEX("200148A8");
如果真的想要这样做,请按照以下方式进行操作。
您无法处理完整地址,但您可以处理最低64位。您可以使用RIGHT(IpAddress, 8)
获取此信息。然后需要将其从二进制转换为十六进制为整数。那你就可以做数学了。
CONV(HEX(RIGHT(IpAddress, 8)), 16, 10) + 1
一旦你完成了它必须与左手边一起放回去。为此,必须将其转换回十六进制表示并填充为16位数。
B -> 0000000000000000000000000000000B
LPAD( HEX(CONV(HEX(RIGHT(IpAddress, 8)), 16, 10) + 1), 32, '0' )
最后,与左侧连接。
CONCAT(
HEX(LEFT(IpAddress, 8)),
LPAD(
HEX(CONV(HEX(RIGHT(IpAddress, 8)), 16, 10) + 1),
32, '0'
)
)
在这两个地方将IpAddress
更改为MAX(IpAddress)
,您就拥有了下一个IP地址。
为了保护每个人的理智,我建议将所有内容放入存储过程中。
我把它作为练习来处理NULL结果(提示:使用CASE)。