Thay đổi động hình học bảng đệm trong PostGIS bằng SQL đơn giản


8

Tôi có hai bảng trong PostGIS, một điểm và một bảng point_buffer. Bảng điểm có trường đệm_distance, với giá trị mặc định là 200. Bây giờ tôi muốn thay đổi hình dạng bảng đệm bất cứ khi nào tôi thay đổi giá trị đệm_distance trong bảng điểm của mình. Tôi có thể làm điều này cho một hàng trong bảng point_buffer của mình bằng cách sử dụng như sau:

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

Nhưng bất cứ khi nào tôi đang cố gắng thay đổi toàn bộ bảng point_buffer (bỏ mệnh đề WHERE trong truy vấn phụ của tôi), tôi nhận được thông báo lỗi:

'LRI: nhiều hơn một hàng được trả về bởi một truy vấn con được sử dụng làm biểu thức'.

Câu hỏi của tôi là, tôi có thể thay đổi toàn bộ bảng point_buffer trong một lần không? Tôi biết một tùy chọn đang sử dụng cho lopp, với giới hạn trên là giá trị đếm của bảng điểm của tôi và tăng giá trị point.gid. Nhưng tôi muốn làm điều này trong SQL đơn giản .

Câu trả lời:


5

Điều đó sẽ hoạt động nếu bạn muốn thay đổi tất cả bộ đệm thành 500:

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

Có thể một khung nhìn sẽ có ý nghĩa hơn, điều đó thực sự năng động, không cần cập nhật:

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

Cảm ơn. Tôi biết tôi đang thiếu một cái gì đó rất ngớ ngẩn. Tuy nhiên, một thay đổi nhỏ là có trong giải pháp của bạn. Mệnh đề WHERE phải là WHERE point_buffer.gid = point.gid . Có một quan điểm sẽ thực sự có ý nghĩa hơn. Tôi cũng đã suy nghĩ theo hướng đó.
thelastray

6

Bạn có thể sử dụng chế độ xem, nhưng bạn cũng có thể sử dụng trình kích hoạt để tự động cập nhật bảng đệm của mình khi bạn sửa đổi bảng điểm ban đầu. Điều này thực sự hữu ích nếu bạn không muốn tạo lại bộ đệm mỗi khi bạn xem bảng của mình, vì tính toán bộ đệm là một nhiệm vụ chuyên sâu về cpu.

Dưới đây là một mẫu mã đầy đủ thực hiện nó: bảng điểm và bảng point_buffer được cập nhật tự động dựa trên các sửa đổi của bảng điểm.

Bạn có thể kiểm tra nó với QGIS: mở cả hai bảng, vào chế độ chỉnh sửa trên bảng điểm. Di chuyển một điểm hoặc thay đổi giá trị đệm_distance và mỗi khi bạn lưu, lớp đệm sẽ được cập nhật.

thưởng thức :)

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;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.