Question analytique Oracle
-
06-07-2019 - |
Question
Soit une fonction zipdistance (zipfrom, zipto) qui calcule la distance (en miles) entre deux codes postaux et les tableaux suivants:
create table zips_required(
zip varchar2(5)
);
create table zips_available(
zip varchar2(5),
locations number(100)
);
Comment puis-je construire une requête qui me renvoie chaque code postal de la table zips_required et la distance minimale qui produirait une somme (emplacements) > = n.
Jusqu'à présent, nous venons d'exécuter une boucle exhaustive en interrogeant chaque rayon jusqu'à ce que nous remplissions les critères.
--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
Cela peut prendre un certain temps sur une grande liste. On a le sentiment que cela pourrait être fait avec une requête analytique Oracle du type:
min() over (
partition by zips_required.zip
order by zipdistance( zips_required.zip, zips_available.zip)
--range stuff here?
)
Les seules requêtes analytiques que j'ai effectuées ont été & "row_number over (partition par order by) &"; basé, et je marche dans des zones inconnues avec cela. Toute orientation à ce sujet est grandement appréciée.
La solution
C’est ce que j’ai trouvé:
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
- Pour chaque
zip_required
calculez la distance jusqu'auzip_available
et triez-le par distance - Pour chaque
count
range
,zip_availables
avec <=> vous permet de savoir combien de <=> se trouvent dans le rayon de cette distance. - filtre (premier où COUNT (emplacements) > N)
Je créais des exemples de données:
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;
/
Remarque: vous avez utilisé COUNT (emplacements) et SUM (emplacements) dans votre question. J'ai supposé qu'il s'agissait de COUNT (emplacements)
Autres conseils
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
Pour chaque zip_required
, ceci sélectionnera la distance minimale à laquelle correspondent les N
zip_available
, ou la distance maximale si le nombre de <=> est inférieur à <=>.
J'ai résolu le même problème en créant un sous-ensemble de ZIP dans un rayon carré à partir du zip indiqué (calcul facile: < ou > NSWE radius), puis en parcourant chaque entrée du sous-ensemble pour voir si c'était dans le rayon nécessaire. Travaillé comme un charme et était très rapide.
J'avais des exigences en partie similaires dans l'un de mes anciens projets ... pour calculer la distance entre 2 codes postaux aux États-Unis. Pour résoudre le même problème, j'avais beaucoup utilisé les données spatiales américaines. L'approche consistait essentiellement à obtenir le code postal source (latitude, longitude) et le code postal de destination (latitude, longitude). Maintenant, j'avais appliqué une fonction pour obtenir la distance en fonction de ce qui précède. La formule de base qui facilite ce calcul est disponible dans le site suivant . J'avais également validé le résultat en faisant référence à ce site ...
Remarque: Cependant, cela fournira des distances approximatives, vous pouvez donc l'utiliser en conséquence. Les avantages sont une fois construit son super rapide pour aller chercher les résultats.