Схема на таблица
За да наложите вашето правило, просто декларирайте pvanlagen.buildid УНИКАЛНО
:
ALTER TABLE pvanlagen ADD CONSTRAINT pvanlagen_buildid_uni UNIQUE (buildid);
building.gid е PK, както разкри вашата актуализация. За да наложите референтна цялост, добавете ВЪНШЕН КЛЮЧ ограничение
към buildings.gid .
Досега сте внедрили и двете. Но би било по-ефективно да стартирате голямото UPDATE по-долу преди вие добавяте тези ограничения.
Има още много неща, които трябва да се подобрят в дефиницията на вашата таблица. Например, buildings.gid както и pvanlagen.buildid трябва да е тип цяло число (или евентуално bigint ако изгаряте много на PK стойности). числов е скъпа глупост.
Нека се съсредоточим върху основния проблем:
Основна заявка за намиране на най-близката сграда
Случаят не е толкова прост, колкото може да изглежда. Това е "най-близък съсед" проблем, с допълнителното усложнение на уникалното присвояване.
Тази заявка намира най-близкия един сграда за всяка PV (съкратено от PV Anlage - ред в pvanlagen ), където нито един от тях все още не е присвоен:
SELECT pv_gid, b_gid, dist
FROM (
SELECT gid AS pv_gid, ST_Transform(geom, 31467) AS geom31467
FROM pvanlagen
WHERE buildid IS NULL -- not assigned yet
) p
, LATERAL (
SELECT b.gid AS b_gid
, round(ST_Distance(p.geom31467
, ST_Transform(b.centroid, 31467))::numeric, 2) AS dist -- see below
FROM buildings b
LEFT JOIN pvanlagen p1 ON p1.buildid = b.gid -- also not assigned ...
WHERE p1.buildid IS NULL -- ... yet
-- AND p.gemname = b.gemname -- not needed for performance, see below
ORDER BY p.geom31467 <-> ST_Transform(b.centroid, 31467)
LIMIT 1
) b;
За да направите тази заявка бърза, витрябва пространствен, функционален GiST индекс на сгради за да го направимного по-бързо:
CREATE INDEX build_centroid_gix ON buildings USING gist (ST_Transform(centroid, 31467));
Не съм сигурен защо ти не
Свързани отговори с повече обяснения:
- Пространствена заявка за голяма таблица с множество самосъединявания, изпълняващи се бавно
- Как да направя заявка за всички редове в радиус от 5 мили от моите координати?
Допълнителна информация:
- https://workshops.boundlessgeo.com/postgis-intro/knn. html
- https://www.postgresonline.com/journal/archives/306-KNN-GIST-with-a-Lateral-twist-Coming-soon-to-a-database-near- you.html
С индекса на място не е необходимо да ограничаваме съвпаденията до едно и също gemname за изпълнение. Направете това само ако това е действително правило, което трябва да се прилага. Ако трябва да се спазва през цялото време, включете колоната в ограничението FK:
Оставащ проблем
Можем да използваме горната заявка в АКТУАЛИЗАЦИЯ изявление. Всяка PV се използва само веднъж, но повече от една PV все пак може да намерят същата сграда да си най-близо. Разрешавате само един PV на сграда. И така, как бихте разрешили това?
С други думи, как бихте присвоили обекти тук?
Просто решение
Едно просто решение би било:
UPDATE pvanlagen p1
SET buildid = sub.b_gid
, dist = sub.dist -- actual distance
FROM (
SELECT DISTINCT ON (b_gid)
pv_gid, b_gid, dist
FROM (
SELECT gid AS pv_gid, ST_Transform(geom, 31467) AS geom31467
FROM pvanlagen
WHERE buildid IS NULL -- not assigned yet
) p
, LATERAL (
SELECT b.gid AS b_gid
, round(ST_Distance(p.geom31467
, ST_Transform(b.centroid, 31467))::numeric, 2) AS dist -- see below
FROM buildings b
LEFT JOIN pvanlagen p1 ON p1.buildid = b.gid -- also not assigned ...
WHERE p1.buildid IS NULL -- ... yet
-- AND p.gemname = b.gemname -- not needed for performance, see below
ORDER BY p.geom31467 <-> ST_Transform(b.centroid, 31467)
LIMIT 1
) b
ORDER BY b_gid, dist, pv_gid -- tie breaker
) sub
WHERE p1.gid = sub.pv_gid;
Използвам DISTINCT ON (b_gid) да се намали точно до един ред на сграда, избирайки PV с най-късото разстояние. Подробности:
За всяка сграда, която е най-близка за повече един PV, се присвоява само най-близкият PV. PK колоната gid (псевдоним pv_gid ) служи като тайбрек, ако двама са еднакво близки. В такъв случай някои PV отпадат от актуализацията и остават неприсвоени . Повтаряне заявката, докато всички PV бъдат присвоени.
Това все още е опростен алгоритъм , обаче. Гледайки моята диаграма по-горе, това присвоява сграда 4 на PV 4 и сграда 5 на PV 5, докато 4-5 и 5-4 вероятно биха били по-добро решение като цяло ...
Отстрани:въведете за dist колона
В момента използвате numericкод>
за него. първоначалната ви заявка присвои постоянно цяло число , без значение в numeric .
В новата ми заявка ST_Distance()
връща действителното разстояние в метри като double прецизност
. Ако просто присвоим това, получаваме около 15 дробни цифри в numeric тип данни и числото не е това точно като начало. Сериозно се съмнявам, че искате да губите хранилището.
Предпочитам да запазя оригиналния double precision от изчислението. или, още по-добре , кръгли според нуждите. Ако измервателните уреди са достатъчно точни, просто преобразувайте и запазете цяло число (автоматично закръгляване на числото). Или първо умножете със 100, за да спестите cm:
(ST_Distance(...) * 100)::int
