Unterschied zwischen zwei Ebenen in PostGIS

8

Was ist der richtige Weg, um die Differenz zwischen zwei Schichten zu berechnen? Ich habe versucht, den folgenden Ansatz zu verwenden:

SELECT ST_Difference(river.geom, lakes.geom) 
FROM river LEFT JOIN lakes ON ST_Intersects(river.geom, lakes.geom) 

Aber in der Ausgabe verliere ich die Geometrien der riverEbene, die keine Geometrien in schneiden lakes. Es sieht so aus, als ob Left Join nicht wie erwartet funktioniert.

Derzeit verwende ich einen anderen Ansatz, bin mir jedoch nicht sicher, ob dies korrekt ist:

SELECT ST_Difference(river.geom, lakes.geom) 
FROM river JOIN lakes ON ST_Intersects(river.geom, lakes.geom) 
UNION 
SELECT river.geom 
FROM river JOIN lakes ON NOT ST_Intersects(river.geom, lakes.geom) 
drnextgis
quelle

Antworten:

11

Mach das einfach:

SELECT COALESCE(ST_Difference(river.geom, lakes.geom), river.geom) As river_geom 
FROM river LEFT JOIN lakes ON ST_Intersects(river.geom, lakes.geom);

umkehren

SELECT COALESCE(ST_Difference(river.geom, lakes.geom), lakes.geom) As lake_geom 
FROM lakes LEFT JOIN river ON ST_Intersects(river.geom, lakes.geom);

Dafür gibt es COALESCE. Ich bevorzuge es sehr, die Semantik von PostGIS so zu halten, wie sie ist. Dies steht im Einklang mit der von der relationalen DB akzeptierten Technologie. Wenn wir diesbezüglich Zugeständnisse machen, müssen wir dies für alle Funktionen tun, und dann sind die Ergebnisse unvorhersehbar.

LR1234567
quelle
Ich glaube nicht, dass Stackexchange meine Änderungen übernimmt. Was ich sagen wollte war COALESCE (ST_Difference (river.geom, lakes.geom), river.geom) Als river_geom ... Fluss LEFT JOIN Seen. Aber hoffentlich haben Sie die Idee
LR1234567
6

Das Problem hierbei ist nicht die linke Verknüpfung, die wie erwartet funktioniert. Wenn die Abfrage jedoch an einen Fluss gelangt, der sich nicht mit einem See schneidet, wird die ST_Difference-Funktion mit NULL als zweitem Argument gespeist, das scheinbar null zurückgibt.

/ Nicklas

Nicklas Avén
quelle
2
Ich denke, NULL zurückzugeben ist das Richtige? Wie Paul erwähnte - es sollte sich wie btrim usw. verhalten. Wenn Sie nur das erste Argument zurückgeben möchten, wenn keine Übereinstimmung vorliegt, würden Sie COALESCE verwenden. Die Verbindung würde den See nicht zurückgeben, wenn der Unterschied leer wäre. Das Ändern dieses Verhaltens würde viel Code beschädigen - da sich Menschen, die sich auf dieses Verhalten verlassen, um die Reihenfolge der Argumente usw. kümmern müssten. zB COALESCE (ST_Difference ..., river.geom, the_world); Mit COALESCE können Sie eine unbestimmte Anzahl von Argumenten anwenden und es ist die Standardmethode, mit der Datenbankprogrammierer mit NULL umgehen.
LR1234567
Ja, Sie haben natürlich Recht :-) Ich habe noch nie darüber nachgedacht, warum der Join einen undefinierten Wert anstelle eines leeren oder nichts zurückgeben muss, wenn keine Übereinstimmung vorliegt.
Nicklas Avén