在PostgreSQL DB中我有表blocks
,它是从GeoLite2-City-Blocks.csv导入的,具有以下结构:
network_start_ip cidr NOT NULL,
network_mask_length integer NOT NULL,
geoname_id bigint,
registered_country_geoname_id bigint,
represented_country_geoname_id bigint,
postal_code character(50),
latitude DOUBLE PRECISION,
longitude DOUBLE PRECISION,
is_anonymous_proxy boolean,
is_satellite_provider boolean
存储IP地址使用的是CIDR数据类型,但是在GeoLite2-City-Blocks.csv中只有START_IP_ADDRESS和MASK_LENGTH。
此表中的数据示例:
::ffff:1.0.0.0/128 120 2077456 2077456 ....
如何选择包含我的IP地址的行,例如87.197.148.121?是否需要计算END_IP_ADDRESS来分隔列?
答案 0 :(得分:0)
您将要使用inet / cidr的包含运算符:
select * from blocks
where set_masklen(network_start_ip,network_mask_length) >>= '::ffff:87.197.148.121'::inet;
有几个问题。首先,数据表示将网络和掩码拆分为不同的字段,因此该查询效率非常低。这两个字段可以简单地组合如下:
alter table blocks add column net_ip inet;
然后会有一次数据迁移:
update blocks set net_ip = set_masklen(network_start_ip,network_mask_length);
然后上面的查询将更容易理解:
select * from blocks where net_ip >>= '87.197.148.121'::inet;
但是,我仍然认为此查询无效,因为net_ip数据以ipv6表示,比较在ip4v中。您可以编写转换函数,或者:
select * from blocks where net_ip >>= concat('::ffff:', '87.197.148.121')::inet;
这根本不是最佳选择。 net_ip未编入索引。要做到这一点,你需要ip4r扩展为postgres。