2013-04-01 3 views
3

Я хотел бы преобразовать inet отформатированный IPv4-адрес в целые компоненты.Как извлечь октеты из значения inet в sql после sql?

Например, поверните '101.255.30.40' в oct1 = 101, oct2 = 255, oct3 = 30 и oct4 = 40.

Есть выражения регулярных выражений, которые должны делать это, если я делаю inet как varchar, но это кажется неэлегантным. Есть ли 1-строчная функция для возврата n-го октета в inet?

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

Для этого нет стандартной функции, и помните, что поля inet и cidr также могут содержать адреса и префиксы IPv6. –

+0

Для моего конкретного приложения все мои адреса - IPv4. –

+0

Похоже, мне нужна версия postet для inet_aton и inet_ntoa, поэтому я могу следить за этим: http://www.hiregion.com/2010/07/converting-ip-address -to-integer-and.html –

ответ

2

я, наконец, получил отличный ответ от сотрудника ...

Для некоторых разновидностей sql, используйте «split_part» вместе с хостом (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, используйте маску, чтобы ускорить работу вместе с делом заявлением, чтобы получить версию 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 

, вы можете добавить преобразование hex-to-int в оператор case, если вы хотите вместо этого указать IPv6 как число.

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

+0

Это работает - спасибо! –

3

Если вы не хотите, чтобы попытаться внести свой вклад в функцию инет типа данных, вы должны полагаться на строки на основе версии. Может быть, поставить что-то вроде этого (но с некоторой проверкой ошибок) в функцию 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