如何在 1 列中对 IPv4 和 IPv6 地址进行排序
How to sort IPv4 and IPv6 addresses within 1 column
IPCIDR FLAG_V6
-------------------------------- ----------
58.97.1.12/30
58.97.1.16/30
58.97.1.96/30
58.97.1.100/30
58.97.1.116/30
2001:fb0:1061:99:0:0:0:0 /64 1
2001:fb0:1061:9a:0:0:0:0 /64 1
2001:fb0:1061:9f:0:0:0:0 /64 1
2001:fb0:1061:a2:0:0:0:0 /64 1
我要排序ipv4
order by (to_number(substr(ipcidr,1,instr(ipcidr,'.')-1))
, to_number(substr(ipcidr,instr(ipcidr,'.')+1, instr(ipcidr,'.',1,2) - instr(ipcidr,'.') - 1))
, to_number(substr(ipcidr,instr(ipcidr,'.',1,2)+1, instr(ipcidr,'.',1,3) - instr(ipcidr,'.',1,2) - 1))
, to_number(substr(ipcidr,instr(ipcidr,'.',1,3)+1,instr(ipcidr,'/')-instr(ipcidr,'.',1,3) - 1))
, to_number(substr(ipcidr,instr(ipcidr,'/')+1)))
并在一列中对 ipv6 进行排序,如果 ipv6 设置为 1,则我有 FLAG_V6 列,否则为 null
您可以使用此函数将 IP 地址转换为整数:
-- Convert a binary/octal/hex number into a decimal value
CREATE FUNCTION Base2Dec(BaseString IN VARCHAR2, Base IN PLS_INTEGER DEFAULT 16) RETURN NUMBER DETERMINISTIC IS
BaseNumber NUMBER := 0;
HexString CONSTANT CHAR(16) := '0123456789ABCDEF';
BEGIN
IF BaseString IS NULL THEN
RETURN NULL;
ELSIF Base NOT IN (2, 8, 16) THEN
RAISE VALUE_ERROR;
ELSIF Base = 16 THEN
RETURN TO_NUMBER(BaseString, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
ELSE
FOR i IN 1..LENGTH(BaseString) LOOP
BaseNumber := BaseNumber * Base + INSTR(HexString, UPPER(SUBSTR(BaseString, i, 1))) - 1;
END LOOP;
RETURN BaseNumber;
END IF;
END Base2Dec;
CREATE FUNCTION UncompressIpV6(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
IpFull VARCHAR2(40);
BEGIN
IF REGEXP_LIKE(Ip, '::') THEN
IpFull := REGEXP_REPLACE(REGEXP_REPLACE(Ip, '^::', '0::'), '::$', '::0');
WHILE REGEXP_COUNT(IpFull, ':') <= 7 LOOP
IpFull := REGEXP_REPLACE(IpFull, '::', ':0::');
END LOOP;
RETURN REGEXP_REPLACE(IpFull, '::', ':');
ELSE
RETURN Ip;
END IF;
END UncompressIpV6;
CREATE FUNCTION Ip2Decimal(IP IN VARCHAR2) RETURN NUMBER DETERMINISTIC IS
DecimalIp NUMBER := 0;
BEGIN
IF REGEXP_LIKE(IP, ':') THEN
SELECT SUM(Base2Dec(REGEXP_SUBSTR(UncompressIpV6(IP), '[[:xdigit:]]+', 1, LEVEL), BASE_HEX) * POWER(65536, 8-LEVEL))
INTO DecimalIp
FROM dual
CONNECT BY LEVEL <= 8;
RETURN DecimalIp;
ELSE
SELECT SUM(REGEXP_SUBSTR(IP, '\d+', 1, LEVEL) * POWER(256, 4-LEVEL))
INTO DecimalIp
FROM dual
CONNECT BY LEVEL <= 4;
RETURN DecimalIp;
END IF;
END Ip2Decimal;
它适用于 IPv4 和 IPv6。将它仅用于 IPv4 应该是很明显的。 IPv6 工作。
您可以在 ORDER BY 子句中使用它:
ORDER BY FLAG_V6 NULLS FIRST, Ip2Decimal(IPCIDR)
IPCIDR FLAG_V6
-------------------------------- ----------
58.97.1.12/30
58.97.1.16/30
58.97.1.96/30
58.97.1.100/30
58.97.1.116/30
2001:fb0:1061:99:0:0:0:0 /64 1
2001:fb0:1061:9a:0:0:0:0 /64 1
2001:fb0:1061:9f:0:0:0:0 /64 1
2001:fb0:1061:a2:0:0:0:0 /64 1
我要排序ipv4
order by (to_number(substr(ipcidr,1,instr(ipcidr,'.')-1))
, to_number(substr(ipcidr,instr(ipcidr,'.')+1, instr(ipcidr,'.',1,2) - instr(ipcidr,'.') - 1))
, to_number(substr(ipcidr,instr(ipcidr,'.',1,2)+1, instr(ipcidr,'.',1,3) - instr(ipcidr,'.',1,2) - 1))
, to_number(substr(ipcidr,instr(ipcidr,'.',1,3)+1,instr(ipcidr,'/')-instr(ipcidr,'.',1,3) - 1))
, to_number(substr(ipcidr,instr(ipcidr,'/')+1)))
并在一列中对 ipv6 进行排序,如果 ipv6 设置为 1,则我有 FLAG_V6 列,否则为 null
您可以使用此函数将 IP 地址转换为整数:
-- Convert a binary/octal/hex number into a decimal value
CREATE FUNCTION Base2Dec(BaseString IN VARCHAR2, Base IN PLS_INTEGER DEFAULT 16) RETURN NUMBER DETERMINISTIC IS
BaseNumber NUMBER := 0;
HexString CONSTANT CHAR(16) := '0123456789ABCDEF';
BEGIN
IF BaseString IS NULL THEN
RETURN NULL;
ELSIF Base NOT IN (2, 8, 16) THEN
RAISE VALUE_ERROR;
ELSIF Base = 16 THEN
RETURN TO_NUMBER(BaseString, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
ELSE
FOR i IN 1..LENGTH(BaseString) LOOP
BaseNumber := BaseNumber * Base + INSTR(HexString, UPPER(SUBSTR(BaseString, i, 1))) - 1;
END LOOP;
RETURN BaseNumber;
END IF;
END Base2Dec;
CREATE FUNCTION UncompressIpV6(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
IpFull VARCHAR2(40);
BEGIN
IF REGEXP_LIKE(Ip, '::') THEN
IpFull := REGEXP_REPLACE(REGEXP_REPLACE(Ip, '^::', '0::'), '::$', '::0');
WHILE REGEXP_COUNT(IpFull, ':') <= 7 LOOP
IpFull := REGEXP_REPLACE(IpFull, '::', ':0::');
END LOOP;
RETURN REGEXP_REPLACE(IpFull, '::', ':');
ELSE
RETURN Ip;
END IF;
END UncompressIpV6;
CREATE FUNCTION Ip2Decimal(IP IN VARCHAR2) RETURN NUMBER DETERMINISTIC IS
DecimalIp NUMBER := 0;
BEGIN
IF REGEXP_LIKE(IP, ':') THEN
SELECT SUM(Base2Dec(REGEXP_SUBSTR(UncompressIpV6(IP), '[[:xdigit:]]+', 1, LEVEL), BASE_HEX) * POWER(65536, 8-LEVEL))
INTO DecimalIp
FROM dual
CONNECT BY LEVEL <= 8;
RETURN DecimalIp;
ELSE
SELECT SUM(REGEXP_SUBSTR(IP, '\d+', 1, LEVEL) * POWER(256, 4-LEVEL))
INTO DecimalIp
FROM dual
CONNECT BY LEVEL <= 4;
RETURN DecimalIp;
END IF;
END Ip2Decimal;
它适用于 IPv4 和 IPv6。将它仅用于 IPv4 应该是很明显的。 IPv6 工作。
您可以在 ORDER BY 子句中使用它:
ORDER BY FLAG_V6 NULLS FIRST, Ip2Decimal(IPCIDR)