2009-06-23 13 views
6

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

create table zips_required(
    zip varchar2(5) 
); 

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

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

Hasta ahora solo hemos ejecutado un bucle exhaustivo preguntando por cada radio hasta que cumplamos 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 llevar un tiempo en una lista grande. Se siente como si esto se podría hacer con una consulta analítica oráculo 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? 
) 

Las únicas consultas analíticas que he hecho han sido "ROW_NUMBER sobre (partición por orden por)" basada, y estoy pisando en áreas desconocidas con esto. Cualquier orientación sobre esto es muy apreciada.

Respuesta

2

Esto es lo que 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 la count con range le permite saber cómo muchos zip_availables están en el radio de esa distancia.
  3. filtro (primera donde COUNT (locations)> N)

que utiliza 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: que utilizó COUNT (ubicaciones) y la suma (ubicaciones) en su pregunta, supuse que era count (ubicaciones)

1
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 encaja Nzip_available 's, o la distancia máxima si el número de zip_available' s es menor que N.

+0

Creo que esto está cerca. En su ejemplo, rn solo será la clasificación de la distancia entre 2 cremalleras ordenadas por la distancia. Lo que necesito es el zipdistance del último en esa lista que suma la suma de sus ubicaciones más todas las ubicaciones anteriores es mayor o igual que N. –

+0

@Josh: esto devolverá la distancia de la ubicación más alejada con la N más cercana. ¿No es lo que quieres? – Quassnoi

+0

límite 1 en una consulta de Oracle? Me perdí algo. – tuinstoel

1

he resuelto el mismo problema mediante la creación de un subconjunto de postal de un radio cuadrado de la cremallera dado (matemáticas fácil: < o> NSWE radio), entonces iteratin g a través de cada entrada en el subconjunto para ver si estaba dentro del radio necesario. Trabajó como un encanto y fue muy rápido.

0

Tenía requisitos en parte similares en uno de mis proyectos anteriores ... para calcular la distancia entre 2 códigos postales en los EE. UU. Para resolver el problema, 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, luego he aplicado una función para obtener la distancia en función de lo anterior. La fórmula base que ayuda en hacer este cálculo está disponible en el following site También había validado el resultado haciendo referencia a this site ...

Nota: Sin embargo, esto proporcionará distancias aproximadas, por lo que uno puede usar esta consecuencia. Los beneficios una vez que se construyen son superrápidos para obtener los resultados.