5 votos

Calcular los valores de todas lat/long en otra tabla en donde base cálculo

Estoy trabajando con datos en Postgresql+PostGIS y me he sorprendido a mí mismo (probablemente de overthinking). Para cada uno de lat/long en un site tabla, quiero calcular un promedio de un campo para todos los puntos dentro de una cierta distancia de la lat/long. Por ejemplo:

SELECT
       site.id,
       ring1.avg as r1_avg,
       ring5.avg as r5_avg
FROM
       (SELECT id, lon, lat FROM sites) as site,
       (SELECT avg(sales) FROM revenue WHERE ST_DWithin(geom::geography, ST_SetSRID(ST_MakePoint(site.lon, site.lat)::geography, 4326), (1.0*1609.34))) as ring1,
       (SELECT avg(sales) FROM revenue WHERE ST_DWithin(geom::geography, ST_SetSRID(ST_MakePoint(site.lon, site.lat)::geography, 4326), (5.0*1609.34))) as ring5;

Yep, lo implícito/explícito de la sintaxis es la mala forma y el mal. Eso es lo que yo estoy luchando con: cómo conseguir el subconsultas para la recolección de la lat/long de la site tabla y el uso para el WHERE cálculo?

5voto

Cohen Puntos 1649

Si usted está usando una versión reciente de PostgreSQL, puede utilizar LATERAL se Une a solucionar el problema de la dependencia en su COMBINACIÓN.

Sin LATERAL, cada una subconsulta en la cláusula FROM se evalúa de forma independiente y no puede hacer referencia cruzada a cualquier otro elemento en la cláusula FROM. El LATERAL de la palabra clave puede preceder a una sub-consulta para permitir la referencia a las columnas de a PARTIR de los elementos que aparecen antes (a la izquierda).

En su caso, usted puede añadir el LATERAL de palabras clave antes de los últimos dos subconsultas.

SELECT
       site.id,
       ring1.avg as r1_avg,
       ring5.avg as r5_avg
FROM
       (SELECT id, lon, lat FROM sites) as site,
       LATERAL (SELECT avg(sales) FROM revenue WHERE ST_DWithin(geom::geography, ST_SetSRID(ST_MakePoint(site.lon, site.lat)::geography, 4326), (1.0*1609.34))) as ring1,
       LATERAL (SELECT avg(sales) FROM revenue WHERE ST_DWithin(geom::geography, ST_SetSRID(ST_MakePoint(site.lon, site.lat)::geography, 4326), (5.0*1609.34))) as ring5;

0voto

Kristi Puntos 1

La unión de dos veces el mismo de las tablas puede ser un poco lento.

Usted puede unirse a una vez y hacer uso de la función de Filtro para las agregaciones (las Versiones anteriores de CASO de uso CUANDO dentro de la función de Agregado).

PostgreSQL > 9.4:

SELECT
   site.id,
   avg(revenue.sales) FILTER (WHERE ST_DWithin(revenue.geog, site.geog, (1.0*1609.34))) as r1_avg,
   avg(revenue.sales) as r5_avg
FROM
   ( select id, ST_SetSRID(ST_MakePoint(site.lon, site.lat)::geography as geog from site) as site
JOIN
   ( select sales, geom::geography as geog from revenue) as revenue
ON ST_DWithin(revenue.geog, site.geog, (5.0*1609.34));

PostgreSQL < 9.4:

cambio de la línea de la r1_avg con los siguientes:

avg(case when ST_DWithin(revenue.geog, site.geog, (1.0*1609.34)) then revenue.sales end) as r1_avg,

Para la mejora del desempeño considerar la posibilidad de crear un índice en revenue.geom::geography

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X