Domanda

Data una funzione zipdistance (zipfrom, zipto) che calcola la distanza (in miglia) tra due codici postali e le seguenti tabelle:

create table zips_required(
   zip varchar2(5)
);

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

Come posso costruire una query che mi restituirà ogni codice postale dalla tabella zips_required e la distanza minima che produrrebbe una somma (posizioni) > = n.

Fino ad ora abbiamo appena eseguito un ciclo esaustivo di query per ciascun raggio fino a quando non abbiamo soddisfatto i criteri.

--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

Questo può richiedere del tempo in un ampio elenco. Sembra che questo potrebbe essere fatto con una query analitica Oracle come:

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

Le uniche query analitiche che ho fatto sono state " row_number over (partizione per ordine di) " basato, e sto calpestando aree sconosciute con questo. Qualsiasi consiglio in merito è molto apprezzato.

È stato utile?

Soluzione

Questo è quello che mi è venuto in mente:

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. Per ogni zip_required calcola la distanza da zip_available e ordinali per distanza
  2. Per ogni count il range con zip_availables ti consente di sapere quanti <=> sono nel raggio di quella distanza.
  3. filtro (prima dove COUNT (posizioni) > N)

Ho usato per creare dati di esempio:

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: hai usato COUNT (posizioni) e SUM (posizioni) nella tua domanda, supponevo che fosse COUNT (posizioni)

Altri suggerimenti

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

Per ogni zip_required, verrà selezionata la distanza minima in cui si adattano N zip_available o la distanza massima se il numero di <=> è inferiore a <=>.

Ho risolto lo stesso problema creando un sottoinsieme di ZIP all'interno di un raggio quadrato da quello specificato (semplice matematica: < o > NSWE radius), quindi ripetendo ogni voce del sottoinsieme per vedere se era nel raggio necessario. Ha funzionato come un fascino ed è stato molto veloce.

Avevo requisiti parzialmente simili in uno dei miei vecchi progetti ... per calcolare la distanza tra 2 codici postali negli Stati Uniti. Per risolvere lo stesso avevo fatto un grande uso dei dati spaziali statunitensi. Fondamentalmente l'approccio era quello di ottenere il codice postale di origine (latitudine, longitudine) e il codice postale di destinazione (latitudine, longitudine). Ora avevo applicato una funzione per ottenere la distanza in base a quanto sopra. La formula di base che aiuta a fare questo calcolo è disponibile nel seguente sito Ho anche validato il risultato facendo riferimento a questo sito ...

Nota: tuttavia ciò fornirà distanze approssimative, quindi è possibile utilizzarlo di conseguenza. I vantaggi vengono costruiti una volta superveloci per ottenere i risultati.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top