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.

Était-ce utile?

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
  1. Pour chaque zip_required calculez la distance jusqu'au zip_available et triez-le par distance
  2. Pour chaque count range, zip_availables avec <=> vous permet de savoir combien de <=> se trouvent dans le rayon de cette distance.
  3. 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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top