Схема на таблица
За да наложите вашето правило, просто декларирайте 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 мили от моите координати?
Допълнителна информация:
- http://workshops.boundlessgeo.com/postgis-intro/knn. html
- http://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