Analíticos De Oracle Pregunta
-
06-07-2019 - |
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.
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
- Para cada
zip_required
calcular la distancia a lazip_available
y ordenarlos por distancia - Para cada
zip_required
elcount
conrange
le permite saber cuántoszip_availables
están en el radio de la distancia. - 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.