Diferença entre duas camadas no PostGIS

8

Qual é a maneira correta de calcular a diferença entre duas camadas? Eu tentei usar a seguinte abordagem:

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

Mas na saída, perco as geometrias da rivercamada que não cruzam nenhuma geometria lakes. Parece que a junção esquerda não funciona conforme o esperado.

Atualmente, estou usando outra abordagem, mas não tenho certeza se isso está correto:

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
fonte

Respostas:

11

Apenas faça o seguinte:

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);

reverter

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);

É para isso que existe o COALESCE. Eu prefiro manter a semântica do PostGIS do jeito que são. É consistente com a tecnologia aceita pelo banco de dados relacional e, se fizermos consessões para isso, precisamos fazer isso para todas as funções e, em seguida, os resultados serão imprevisíveis.

LR1234567
fonte
Não acho que a stackexchange esteja levando minhas edições. O que eu quis dizer foi COALESCE (ST_Diferença (river.geom, lakes.geom), river.geom) Como river_geom ... rio LEFT JOIN lagos. Mas esperamos que você entenda a questão #
LR1234567
6

O problema aqui não é a junção esquerda, está funcionando como esperado. Mas quando a consulta chega a um rio que não se cruza com um lago, ela alimenta a função ST_Difference com NULL como o segundo argumento que parece retornar nulo.

/ Nicklas

Nicklas Avén
fonte
2
Eu acho que retornar NULL é a coisa certa a fazer? Como Paulo mencionou - deve se comportar como btrim etc. Se você quisesse retornar o primeiro argumento quando não houvesse correspondência, usaria COALESCE. A junção não retornaria o lago se a diferença estivesse vazia. alterar esse comportamento quebraria muito código - pois as pessoas que dependem desse comportamento precisariam se preocupar com a ordem dos argumentos e assim por diante. por exemplo, COALESCE (ST_Diferença ..., river.geom, the_world); COALESCE permite aplicar um número indefinido de argumentos e é a maneira padrão como programadores de banco de dados lidam com NULL.
LR1234567
Sim, você está certo, é claro :-) Você nunca pensou nisso antes, por que a junção deve retornar um valor indefinido em vez de vazio ou nada quando não há correspondência.
Nicklas Avén