Postgres使用距离连接查询返回正确的结果

时间:2017-01-04 19:31:29

标签: postgresql postgis

我在postgres中创建了一个包含位置及其空间坐标的表格(纬度,经度(以度为单位))。我用于相同的命令是:

我在postgres中将空间坐标插入(经度,纬度)

我在postgres中创建了一个包含位置及其空间坐标的表格(纬度,经度(以度为单位))。我用于相同的命令是:

CREATE TABLE spatialTest(
  name character varying(100),
  the_geo geography
);
\copy spatialTest(name,the_geo) FROM 'testSpatial.csv' DELIMITERS E'\t' CSV;

testSpatial.csv包含以下值:

A   SRID=4326;POLYGON((0.178773 -127.681841,0.178711 -127.681962,0.179125 -127.682083,0.179176 -127.682006,0.179153 -127.681986,0.179143 -127.681962,0.179147 -127.681935,0.179166 -127.681913,0.179195 -127.681897,0.179244 -127.681886,0.179284 -127.681887,0.179336 -127.681904,0.179464 -127.681757,0.179489 -127.681736,0.179429 -127.681680,0.179370 -127.681516,0.179221 -127.681331,0.179184 -127.681185,0.179051 -127.681264,0.178822 -127.681499,0.178761 -127.681698,0.178796 -127.681703,0.178839 -127.681721,0.178857 -127.681736,0.178861 -127.681740,0.178871 -127.681756,0.178873 -127.681782,0.178859 -127.681809,0.178843 -127.681825,0.178812 -127.681839,0.178773 -127.681841))
B   SRID=4326;POINT(0.628912 -127.700922)

现在我想找到距离彼此相距50公里的所有空间位置。为此,我使用了以下命令:

select s1.name, s2.name  from spatialTest s1, 
     spatialTest s2  where ST_DWithin(s1.the_geo, s2.the_geo, 50000);

然而,令我惊讶的是,我发现尽管A和B之间的距离大于50公里(准确地说是50.0995公里)。使用Chris Veness的大地测量公式(计算距离之间的距离)点和纬度和经度的线段)),但它们由postgres作为结果返回。有人可以帮我弄清楚我哪里出错了。

我使用的是PostgreSQL 9.6devel和Postgis版本,我正在使用的是:POSTGIS =" 2.2.1 r14555"

1 个答案:

答案 0 :(得分:1)

正如其他人所说,你正在加载这个......

NOTICE:  Coordinate values were coerced into range [-180 -90, 180 90] for GEOGRAPHY
CONTEXT:  COPY spatialtest, line 2, column the_geo: "SRID=4326;POINT(0.628912 -127.700922)"

可能,您正在尝试加载(lat,long),而PostgreSQL需要(long,lat)。但是,我们可以解决输入列的排序问题。我们所要做的就是,

  1. 创建临时表as geometry`。

    CREATE TEMP TABLE foo(name text, the_geo geometry);
    
  2. 在导入时删除丢失SRID的SRID位(EKWT)。

    sed -i -e's/SRID=4326;//' ./foo.csv
    
  3. 加载输入。

    \copy foo(name,the_geo) FROM 'foo.csv' DELIMITERS E'\t' CSV;
    
  4. 对点进行重新排序。
  5. 复制到主表。

    INSERT INTO spatialTest(name, the_geo)
    SELECT
      name,
      ST_Union(
        ST_SetSRID(
          ST_MakePoint(st_y(geom), st_x(geom))
        ,4326)
      )::geography
    FROM foo
    CROSS JOIN ST_DumpPoints(foo.the_geo) AS t
    GROUP BY name
    ORDER BY name;
    
  6. 作为旁注:不要将varchar用于名称。只需将其保留为TEXT即可。除非你有充分的理由施加字符限制。

    然后跑完距离..

    SELECT ST_Distance(
      (SELECT the_geo FROM spatialtest WHERE name='A'), (SELECT the_geo FROM spatialtest WHERE name='B')
    );
      st_distance   
    ----------------
     49740.52214618
    (1 row)