如何从postgres sql中的inet值中提取八位字节?

时间:2013-04-01 20:45:03

标签: postgresql ipv4 inet

我想将inet格式化的IPv4地址转换为整数组件。

例如,将'101.255.30.40'变为oct1 = 101,oct2 = 255,oct3 = 30,oct4 = 40。

如果我将inet转换为varchar,那么有正则表达式应该这样做,但这似乎是不优雅的。是否有一行函数用于返回inet的第n个八位字节?

select inet_to_octet('101.255.30.40', 4) as temp;  -- returns temp=40?

3 个答案:

答案 0 :(得分:3)

除非您想尝试将函数贡献给inet数据类型,否则您需要依赖基于字符串的版本。也许把这样的东西(但有一些错误检查)放到一个SQL函数中以便于访问?:

CREATE OR REPLACE FUNCTION extract_octet(inet, integer) RETURNS integer AS $$
    SELECT ((regexp_split_to_array(host($1), E'\\.'))[$2])::int;
$$ LANGUAGE SQL;



select extract_octet(inet '192.26.22.2', 2)

Output: 26

答案 1 :(得分:2)

以下是IPv4地址的单独八位字节的几个单行:

SELECT substring(host('1.2.3.4'::inet) FROM '^([0-9]+)\.[0-9]+\.[0-9]+\.[0-9]+$');

将返回1

SELECT substring(host('1.2.3.4'::inet) FROM '^[0-9]+\.([0-9]+)\.[0-9]+\.[0-9]+$');

将返回2

SELECT substring(host('1.2.3.4'::inet) FROM '^[0-9]+\.[0-9]+\.([0-9]+)\.[0-9]+$');

将返回3

SELECT substring(host('1.2.3.4'::inet) FROM '^[0-9]+\.[0-9]+\.[0-9]+\.([0-9]+)$');

将返回4

答案 2 :(得分:2)

我终于得到了一位同事的出色答案......

对于某些版本的sql,请使用" split_part"与host(inet)一起获取文本字段。

select split_part(host('101.255.30.40'::inet), '.', 1);
select split_part(host('101.255.30.40'::inet), '.', 2);
select split_part(host('101.255.30.40'::inet), '.', 3);
select split_part(host('101.255.30.40'::inet), '.', 4);

结果

101
255
30
40

如果您想变得更加棘手并处理IPv6,请使用掩码加速操作以及case语句以获取IP版本:

select
   (case
      when family('101.255.30.40'::inet) = 4 then split_part(host(broadcast(set_masklen('101.255.30.40'::inet, 32))), '.', 4)::varchar
      when family('101.255.30.40'::inet) = 6 then split_part(host(broadcast(set_masklen('101.255.30.40'::inet, 64))), ':', 4)::varchar
      else null end)::varchar as octet4;

select
   (case
      when family('2604:8f00:4:80b0:3925:c69c:458:3f7b'::inet) = 4 then split_part(host(broadcast(set_masklen('2604:8f00:4:80b0:3925:c69c:458:3f7b'::inet, 32))), '.', 4)::varchar
      when family('2604:8f00:4:80b0:3925:c69c:458:3f7b'::inet) = 6 then split_part(host(broadcast(set_masklen('2604:8f00:4:80b0:3925:c69c:458:3f7b'::inet, 64))), ':', 4)::varchar
      else null end)::varchar as octet4;

结果

40
80b0

如果要将IPv6转换为数字,则可以在case语句中添加hex-to-int转换。