Pregunta

Dada una función zipdistance(zipfrom,zipto), que calcula la distancia (en millas) entre dos códigos postales y las siguientes tablas:

create table zips_required(
   zip varchar2(5)
);

create table zips_available(
   zip varchar2(5),
   locations number(100)
);

¿Cómo puedo crear una consulta que devuelva a mí cada código postal de la zips_required tabla y la distancia mínima a la que produciría una suma(ubicaciones) >= n.

Hasta ahora sólo hemos ejecutar una exhaustiva bucle de consulta para cada radio de hasta hemos cumplido con los criterios.

--Do this over and over incrementing the radius until the minimum requirement is met
select count(locations) 
from zips_required zr 
left join zips_available za on (zipdistance(zr.zip,za.zip)< 2) -- Where 2 is the radius

Esto puede tomar un tiempo en una larga lista.Se siente como esto se podría hacer con un analíticos de oracle consulta a lo largo de las líneas de:

min() over (
  partition by zips_required.zip 
  order by zipdistance( zips_required.zip, zips_available.zip)
  --range stuff here?
) 

La única analítica de las consultas que he hecho han sido "row_number over (partition by order by)" basado, y estoy pisando en áreas desconocidas con esto.Cualquier orientación sobre esto es muy apreciado.

¿Fue útil?

Solución

Esto es lo que se me ocurrió :

SELECT zr, min_distance
  FROM (SELECT zr, min_distance, cnt, 
               row_number() over(PARTITION BY zr ORDER BY min_distance) rnk
           FROM (SELECT zr.zip zr, zipdistance(zr.zip, za.zip) min_distance,
                         COUNT(za.locations) over(
                             PARTITION BY zr.zip 
                             ORDER BY zipdistance(zr.zip, za.zip)
                         ) cnt
                    FROM zips_required zr
                   CROSS JOIN zips_available za)
          WHERE cnt >= :N)
 WHERE rnk = 1
  1. Para cada zip_required calcular la distancia a la zip_available y ordenarlos por distancia
  2. Para cada zip_required el count con range le permite saber cuántos zip_availables están en el radio de la distancia.
  3. filtro (primera donde COUNT(ubicaciones) > N)

He usado para crear datos de ejemplo:

INSERT INTO zips_required
   SELECT to_char(10000 + 100 * ROWNUM) FROM dual CONNECT BY LEVEL <= 5;

INSERT INTO zips_available
   (SELECT to_number(zip) + 10 * r, 100 - 10 * r FROM zips_required, (SELECT ROWNUM r FROM dual CONNECT BY LEVEL <= 9));

CREATE OR REPLACE FUNCTION zipdistance(zipfrom VARCHAR2,zipto VARCHAR2) RETURN NUMBER IS
BEGIN
   RETURN abs(to_number(zipfrom) - to_number(zipto));
END zipdistance;
/

Nota: se utiliza COUNT(ubicaciones) y SUMA(ubicaciones) en tu pregunta, yo supuse que era COUNT(ubicaciones)

Otros consejos

SELECT  *
FROM    (
        SELECT  zip, zd, ROW_NUMBER() OVER (PARTITION BY zip ORDER BY rn DESC) AS rn2
        FROM    (
                SELECT  zip, zd, ROW_NUMBER() OVER (PARTITION BY zip ORDER BY zd DESC) AS rn
                FROM    (
                        SELECT  zr.zip, zipdistance(zr.zip, za.zip) AS zd
                        FROM    zips_required zr
                        JOIN    zips_available za
                        )
                )
        WHERE   rn <= n
        )
WHERE   rn2 = 1

Para cada zip_required, esto seleccionará la distancia mínima en la que se ajustan los N zip_available 's, o la distancia máxima si el número de <=>' s es menor que <=>.

Resolví el mismo problema creando un subconjunto de ZIP dentro de un radio cuadrado desde el zip dado (matemática fácil: < o > radio NSWE), luego iterando a través de cada entrada en el subconjunto para ver si estaba dentro del radio necesario. Funcionó a las mil maravillas y fue muy rápido.

Tenía requisitos en parte similares en uno de mis viejos proyectos ... para calcular la distancia entre 2 códigos postales en los Estados Unidos. Para resolver lo mismo, hice un gran uso de los datos espaciales de EE. UU. Básicamente, el enfoque consistía en obtener el código postal de origen (latitud, longitud) y el código postal de destino (latitud, longitud). Ahora había aplicado una función para obtener la distancia basada en lo anterior. La fórmula base que ayuda a hacer este cálculo está disponible en el siguiente sitio También había validado el resultado haciendo referencia a este sitio ...

Nota: Sin embargo, esto proporcionará distancias aproximadas, por lo que se puede usar esto en consecuencia. Una vez que se construyen los beneficios, es superrápido para obtener los resultados.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top