【问题标题】:Convert IP address in PostgreSQL to integer?将PostgreSQL中的IP地址转换为整数?
【发布时间】:2021-08-08 04:19:09
【问题描述】:

有没有查询可以做到这一点?

例如,给定一个条目 '216.55.82.34' ..我想用 '.' 分割字符串,并应用等式:

IP 编号 = 16777216*w + 65536*x + 256*y + z 其中 IP 地址 = w.x.y.z

这是否可能仅通过一个查询来实现?

【问题讨论】:

  • 这是人们在需要将 MySQL 的 INET_ATON() 函数转换为 Postgres 时想要找到的线程。

标签: postgresql ip


【解决方案1】:

您可以简单地将 inet 数据类型转换为 bigint:(inet_column - '0.0.0.0'::inet)

例如:

SELECT ('127.0.0.1'::inet - '0.0.0.0'::inet) as ip_integer

将输出2130706433,即IP地址127.0.0.1的整数表示

【讨论】:

  • 这不适用于 IPv6,因为它超出了 int 类型的范围。
  • @LtWorf 具体来说,它超出了 bigint 的范围,这是一个 64 位有符号类型,而 IPv6 需要 128 位无符号。
【解决方案2】:

您可以使用split_part()。例如:

CREATE FUNCTION ip2int(text) RETURNS bigint AS $$ 
SELECT split_part($1,'.',1)::bigint*16777216 + split_part($1,'.',2)::bigint*65536 +
 split_part($1,'.',3)::bigint*256 + split_part($1,'.',4)::bigint;
$$ LANGUAGE SQL  IMMUTABLE RETURNS NULL ON NULL INPUT;


SELECT ip2int('200.233.1.2');
>> 3370713346

或者,如果不想定义函数,只需:

SELECT split_part(ip,'.',1)::bigint*16777216 + split_part(ip,'.',2)::bigint*65536 +
 split_part(ip,'.',3)::bigint*256 + split_part(ip,'.',4)::bigint;

后者的缺点是,如果该值是通过某种计算给出的,而不仅仅是一个表字段,那么计算效率可能会低下,或者写起来很难看。

【讨论】:

  • 如果我的列名为 ip,我将如何应用它?有点迷茫
【解决方案3】:

PG 9.4

create or replace function ip2numeric(ip varchar) returns numeric AS
$$
DECLARE
  ip_numeric numeric;
BEGIN
  EXECUTE format('SELECT inet %L - %L', ip, '0.0.0.0') into ip_numeric;

  return ip_numeric;
END;
$$ LANGUAGE plpgsql;

用法

select ip2numeric('192.168.1.2');
$ 3232235778

【讨论】:

    【解决方案4】:
    create function dbo.fn_ipv4_to_int( p_ip text)
    returns int
    as $func$ 
    select cast(case when cast( split_part(p_ip, '.', 1 ) as int ) >= 128
    then 
    (
    ( 256 - cast(split_part(p_ip, '.', 1 ) as int ))
    * 
    -power ( 2, 24 ) 
    )
    + (cast( split_part(p_ip, '.', 2 ) as int ) * 65536 )
    + (cast( split_part(p_ip, '.', 3 ) as int ) * 256 )
    + (cast( split_part(p_ip, '.', 4 ) as int )  )
    
    else (cast(split_part(p_ip, '.', 1 ) as int) * 16777216)
    + (cast(split_part(p_ip, '.', 2 ) as int) * 65536)
    + (cast(split_part(p_ip, '.', 3 ) as int) * 256)
    + (cast(split_part(p_ip, '.', 4 ) as int))
    end as int )
    $func$ LANGUAGE SQL  IMMUTABLE RETURNS NULL ON NULL INPUT;
    

    如果您需要获取 32 位整数。它将返回超过 128.0.0.0 的 ips 的负数。如果可以的话,我会使用 bigint,但是当我将数字存储为来自另一个数据库的 32 位数字时,我有一个案例。

    【讨论】:

      【解决方案5】:

      考虑将列数据类型改为inet,也许效率更高。

      ALTER TABLE iptable ALTER COLUMN ip_from TYPE inet
      USING '0.0.0.0'::inet + ip_from::bigint;
      
      create index on iptable using gist (ip_from inet_ops);
      

      然后去查询

      SELECT ip_from
      FROM iptable 
      WHERE ip_from = '177.99.194.234'::inet
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-20
        • 1970-01-01
        • 2014-03-03
        • 2012-10-26
        • 2011-02-25
        • 1970-01-01
        • 2017-08-23
        • 1970-01-01
        相关资源
        最近更新 更多