Postgres - 如何在插入时自动调用ST_SetSRID(ST_MakePoint(lng,lat),4326)?

时间:2017-11-26 01:00:24

标签: sql database postgresql postgis

我使用的是postGIS,而且我对SQL不是很熟悉。

只要我这样做(伪代码!),我就可以成功插入到我的markers表中:

'INSERT INTO markers(created_by, title, description, lat, lng, geography)\
       values($1, $2, $3, $4::decimal, $5::decimal, ST_SetSRID(ST_MakePoint($5::decimal, $4::decimal), $6))',
      [
        data.created_by,
        data.title,
        data.description,
        data.lat,
        data.lng,
        4326
      ]'

如您所见,我正在从我的应用程序代码中执行ST_SetSRID(ST_MakePoint($5::decimal, $4::decimal), $6)

我想避免这种情况,而是把它放在数据库端。由于我可以在数据库端执行自动时间戳等操作,因此我想知道我是否也可以在桌面上执行ST_SetSRID(ST_MakePoint(lng, lat), 4326)

这样,应用程序只需要提供lat和lng,数据库就会执行ST_SetSRID(ST_MakePoint())操作。

由于

编辑:由于两者都提供了非常好的帮助和建议,我不确定其标记为+1的答案。我希望未来的读者能够阅读并希望学到一些东西!

2 个答案:

答案 0 :(得分:2)

您可以使用触发器执行此操作。您的插入调用不会处理几何,只处理lat-long和其他非空间字段,触发器函数将创建几何。让我们不要忘记在更新行时也这样做。 请注意,我已对SRID进行了硬编码,因为无法将额外的动态参数传递给触发器功能。如果需要,请在表格中添加一个字段以保存此值,您可以将其称为new.srid

CREATE OR REPLACE FUNCTION markers_geog_tg_fn() RETURNS trigger AS
$BODY$BEGIN
  IF TG_OP = 'INSERT' AND (NEW.lat ISNULL or NEW.lng ISNULL  ) THEN
    RETURN NEW; -- no  geometry
  ELSIF TG_OP = 'UPDATE' THEN
    --Lat Long updated to null, erase geometry
    IF NEW.lat ISNULL or NEW.lng ISNULL THEN
        NEW.geography = NULL;
    END IF;

    IF NEW.lat IS NOT DISTINCT FROM OLD.lat and NEW.lng IS NOT DISTINCT FROM OLD.lng THEN
      RETURN NEW; -- same old geometry
    END IF;
  END IF;
  -- Attempt to transform a geometry
  BEGIN
    NEW.geography := ST_SetSRID(ST_MakePoint(NEW.lng::decimal, NEW.lat::decimal), 4326))
  EXCEPTION WHEN SQLSTATE 'XX000' THEN
    RAISE WARNING 'geography  not updated: %', SQLERRM;
  END;
  RETURN NEW;
END;$BODY$ LANGUAGE plpgsql;

CREATE TRIGGER markers_geog_tg BEFORE INSERT OR UPDATE
   ON markers FOR EACH ROW
   EXECUTE PROCEDURE markers_geog_tg_fn();

答案 1 :(得分:1)

  

我想避免这种情况,而是把它放在数据库端。由于我可以在数据库端执行自动时间戳等操作,我想知道我是否也可以在表本身上执行ST_SetSRID(ST_MakePoint(lng, lat), 4326)

真的不是一个好主意,我知道这听起来像个好主意,但似乎很有吸引力。也就是说,你做的工作比你需要的还多。

CREATE TABLE markers (geom geography(POINT,4326) );
INSERT INTO markers(geom) VALUES (ST_MakePoint(0,0));

正如您在此处所见,geography的默认SRID为4326.您不必将其设置为4326,但显式不会受到伤害。此外,将输入转换为ST_MakePoint()为十进制是的想法。 ST_MakePoint仅接受double precision。来自\df ST_MakePoint

的结果
                                                     List of functions
 Schema |     Name     | Result data type |                          Argument data types                           |  Type  
--------+--------------+------------------+------------------------------------------------------------------------+--------
 public | st_makepoint | geometry         | double precision, double precision                                     | normal
 public | st_makepoint | geometry         | double precision, double precision, double precision                   | normal
 public | st_makepoint | geometry         | double precision, double precision, double precision, double precision | normal

所以你可以在这里看到额外演员实际上只是增加了更多的工作。您真正想要的只是ST_MakePoint(lng,lat)列中的简单geography(POINT,4326)

其余任务需要触发器。它还需要一个额外的列lat和long。 虽然我可以告诉你如何这样做,但我强烈建议这样做。

ALTER TABLE markers
  ADD COLUMN lat double precision,
  ADD COLUMN long double precision;

CREATE OR REPLACE FUNCTION do_stupid_stuff()
RETURNS trigger
AS $$
  BEGIN
    NEW.geom = ST_MakePoint(NEW.long, NEW.lat);
    RETURN NEW;
  END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER really_lazy
  AFTER INSERT ON markers
  FOR EACH ROW
  EXECUTE PROCEDURE do_stupid_stuff();