プレーンSQLを使用してPostGISでバッファテーブルジオメトリを動的に変更する


8

PostGISには、pointテーブルとpoint_bufferテーブルの2つのテーブルがあります。ポイントテーブルにはbuffer_distanceフィールドがあり、デフォルト値は200です。ポイントテーブルのbuffer_distance値を変更するたびに、バッファテーブルジオメトリを変更したいと思います。これは、point_bufferテーブルの1つの行に対して次のようにして実行できます。

UPDATE point_buffer
SET the_geom = (SELECT ST_Buffer(the_geom,500) FROM point WHERE gid = 1)
FROM point
WHERE point.gid = point_buffer.gid

しかし、point_bufferテーブル全体(サブクエリにWHERE句を削除)を変更しようとすると、エラーメッセージが表示されます。

「エラー:式として使用されているサブクエリから複数の行が返されました。」

私の質問は、point_bufferテーブル全体を一度に変更できますか?1つのオプションがfor loppを使用していることを知っています。上限はポイントテーブルのカウント値であり、point.gid値を増分します。しかし、私はこれをプレーンSQLで実行したいと考えています

回答:


5

すべてのバッファーを500に変更する場合は、これでうまくいくはずです。

UPDATE point_buffer
SET the_geom = (SELECT ST_Buffer(point.the_geom,500)
                FROM point
                WHERE point.gid = point_buffer.gid);

多分ビューはもっと理にかなっていて、それは本当に動的で、更新は必要ありません:

CREATE VIEW buffers
AS SELECT gid,
          ST_Buffer(the_geom,buffer_distance)
   FROM point;

ありがとう。私は非常にばかげた何かが欠けていることを知っていました。ただし、ソリューションに小さな変更があります。WHERE句はWHERE point_buffer.gid = point.gidである必要があります。はい、ビューは本当に意味があります。私もその方向に考えていました。
thelastray

6

ビューを使用できますが、トリガーを使用して、元のポイントテーブルを変更するときにバッファーテーブルを自動的に更新することもできます。バッファの計算はCPUを集中的に使用するタスクであるため、テーブルを表示するたびにバッファを再生成したくない場合、これは本当に便利です。

これを実装する完全なコードサンプルは次のとおりです。ポイントテーブルと、ポイントテーブルの変更に基づいて自動的に更新されるpoint_bufferテーブル。

QGISでテストできます。両方のテーブルを開き、ポイントテーブルで編集モードに入ります。ポイントを移動するか、またはbuffer_distanceの値を変更すると、保存するたびにバッファーレイヤーが更新されます。

楽しい :)

drop table if exists point;
create table point (
    gid serial primary key
    , point_name varchar
    , buffer_distance double precision
    , the_geom geometry
);

drop table if exists point_buffer;
create table point_buffer (
    gid serial primary key
    , point_gid integer
    , the_geom geometry
);

select populate_geometry_columns();

insert into 
    point (point_name, buffer_distance, the_geom) 
select
    'point ' || n::varchar as point_name
    , random() * 100 + min_buf as buffer_distance
    , st_setsrid(st_point(random() * 10000 + x0, random() * 10000 + y0), 2154) as the_geom
from
        generate_series(1, 1000) as n
        , (values (10)) as foox(x0)
        , (values (10)) as fooy(y0)
        , (values (10)) as buf(min_buf);

-- insert values into point_buffer
insert into
    point_buffer (point_gid, the_geom)
select
    gid as point_gid
    , st_buffer(the_geom, buffer_distance)
from
    point;

-- update all point_buffer
update
    point_buffer as pb
set
    the_geom = st_buffer(p.the_geom, p.buffer_distance)
from
    point as p
where
    p.gid = pb.point_gid;

-- add trigger to automate insert / delete / update
create or replace function update_point_buffer() returns trigger as
$$
begin
    -- delete
    IF (TG_OP = 'DELETE') THEN
        delete from point_buffer as pb where point_gid = OLD.gid;
        return OLD;
    -- insert
    ELSIF (TG_OP = 'INSERT') THEN
        insert into
            point_buffer (point_gid, the_geom)
        select
            NEW.gid as point_gid
            , st_buffer(NEW.the_geom, NEW.buffer_distance);
        return NEW;
    -- update
    else
        update
            point_buffer as pb
        set
            the_geom = st_buffer(NEW.the_geom, NEW.buffer_distance)
        where
            pb.gid = NEW.gid;
        return NEW;
    END IF;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS trg_point_point_buffer ON point;
CREATE TRIGGER trg_point_point_buffer AFTER DELETE OR INSERT OR UPDATE ON point
    FOR EACH ROW EXECUTE PROCEDURE update_point_buffer();

/* use it */

-- insert
insert into 
    point (point_name, buffer_distance, the_geom)
select
    'added point to test trigger' as point_name
    , random() * 100 + min_buf as buffer_distance
    , st_setsrid(st_point(random() * 10000 + x0, random() * 10000 + y0), 2154) as the_geom
from
        (values (10)) as foox(x0)
        , (values (10)) as fooy(y0)
        , (values (10)) as buf(min_buf);

select
    st_astext(pb.the_geom)
    , *
from 
    point_buffer as pb
join
    point as p
on
    p.gid = pb.point_gid
where
    p.point_name = 'added point to test trigger';

-- update
update 
    point as p
set
    the_geom = st_setsrid(st_point(0, 0), 2154)
    , buffer_distance = 1
where
    p.point_name = 'added point to test trigger';

-- check point_buffer
select
    st_astext(pb.the_geom)
    , *
from 
    point_buffer as pb
join
    point as p
on
    p.gid = pb.point_gid
where
    p.point_name = 'added point to test trigger';

-- delete
delete from
    point as p
where
    p.point_name = 'added point to test trigger';

-- check point_buffer
select
    *
from
    point_buffer as pb
where
    point_gid = 1001;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.