| 导言: PostGIS 是业界功能最全面, 能力最强大的空间地理数据库引擎. 现实业务开发中, 经常会遇到有附近的某某的需求, 如何快速实现呢, PostGIS+PostgreSQL 可以帮到你.
本文就讲解如何通过 PostGIS 实现附近的对象这个功能, 实际很简单就一条 SQL 可以搞定.
首先, 我们准备一个 PostgreSQL 数据库实例, 并且此数据库实例需要支持 PostGIS 插件, 版本不挑剔, 此为基本能力.
第一步: 创建插件, 登录到数据库实例中, 在业务 database 执行如下命令:
- \c test
- CREATE EXTENSION postgis;
- CREATE EXTENSION postgis_topology;
第二步: 创建测试表与索引:
- CREATE TABLE t_user(uid int PRIMARY KEY,name varchar(20),location geometry);
- CREATE INDEX t_user_location on t_user USING Gist(location);
第三步: 插入测试数据:
- # 创建一个自动名字生成函数:
- create or replace function random_string(length integer) returns text as
- $$
- declare
- chars text[] := '{0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}';
- result text := '';
- i integer := 0;
- length2 integer := (select trunc(random() * length + 1));
- begin
- if length2 <0 then
- raise exception 'Given length cannot be less than 0';
- end if;
- for i in 1..length2 loop
- result := result || chars[1+random()*(array_length(chars, 1)-1)];
- end loop;
- return result;
- end;
- $$ language plpgsql;
- # 插入一千万条测试数据
- insert into t_user select generate_series(1,10000000), random_string(20),st_setsrid(st_makepoint(150-random()*100, 90-random()*100), 4326);
第四步: 进行附近的人查询.
首先我们在百度地图拾取坐标系统中随便找一个坐标 http://api.map.baidu.com/lbsapi/getpoint/ . 此处用 天安门广场的坐标作为示例: 116.404177,39.909652
第五步: 明确好要查询的坐标, 就直接在数据库中找到这个坐标最近的 5 个对象, 并且输出这五个对象离此地的距离, 此处单位是 百公里.
注意: WGS84 是目前最流行的地理坐标系统. 在国际上, 每个坐标系统都会被分配一个 EPSG 代码, EPSG:4326 就是 WGS84 的代码. GPS 是基于 WGS84 的, 所以通常我们得到的坐标数据都是 WGS84 的. 一般我们在存储数据时, 就仍然按 WGS84 存储.
select uid, name, ST_AsText(location), ST_Distance(ST_GeomFromText('POINT(116.404177 39.909652)',4326), location) from t_user order by location <-> 'SRID=4326;POINT(116.404177 39.909652)'::geometry limit 5;
第六步: 查看此对象 1000 米以内的所有对象与距离:
select uid, name, ST_AsText(location),ST_Distance(ST_GeomFromText('POINT(116.404177 39.909652)',4326), location) from users where ST_DWithin(location::geography, ST_GeographyFromText('POINT(116.404177 39.909652)'), 1000.0);
第七步: 大功告成, 是不是很简单.
补充内容: 国内使用的是火星坐标系, 下面链接中的内容可以在几种坐标系间互相转换,
来源: https://www.qcloud.com/developer/article/1901558