문제

I would like to convert an inet formatted IPv4 address into the integer components.

For example, turn '101.255.30.40' into oct1=101, oct2=255, oct3=30, and oct4=40.

There are regex expressions that should do this if I cast the inet as a varchar, but that seems inelegant. Is there a 1-line function for returning the nth octet of an inet?

select inet_to_octet('101.255.30.40', 4) as temp;  -- returns temp=40?
도움이 되었습니까?

해결책

I finally got an excellent answer from a co-worker...

For some flavors of sql, use "split_part" along with host(inet) to get the text field.

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);

results in

101
255
30
40

If you want to get trickier and handle IPv6, use a mask to speed up the operation along with case statements to get the IP version:

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;

results in

40
80b0

you can then add in a hex-to-int conversion into the case statement if you want to cast the IPv6 as a number instead.

다른 팁

Unless you want to try to contribute the function to the inet datatype, you'll need to rely on a string based version. Maybe put something like this (but with some error checking) into an SQL function for easy access?:

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

Here are a couple of one-liners for the separate octets of an IPv4 address:

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

will return 1

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

will return 2

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

will return 3

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

will return 4

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top