2009-06-23 10 views
6

eine Funktion zipdistance (zipfrom, zipto) gegeben, die die Entfernung (in Meilen) zwischen zwei Postleitzahlen und den folgenden Tabellen berechnet:Oracle Analytic Frage

create table zips_required(
    zip varchar2(5) 
); 

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

Wie kann ich eine Abfrage erstellen, die mir zurück jede Postleitzahl aus der Tabelle zips_required und der Mindestabstand, der eine Summe (Orte)> = n ergeben würde.

Bis jetzt haben wir nur eine umfassende Schleife Abfrage für jeden Radius ausgeführt, bis wir die Kriterien erfüllen.

Dies kann eine Weile auf einer großen Liste dauern. Es fühlt sich an wie diese mit einer Oracle-analytischen Query entlang der Linien von getan werden könnte:

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

Die einzigen analytischen Abfragen Ich habe schon getan haben „ROW_NUMBER über (Partition im Auftrag von)“ basiert, und ich beschreiten in unbekannte Bereiche mit diesem. Jede Anleitung dazu wird sehr geschätzt.

Antwort

2

Das ist, was ich kam mit:

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. Für jeden zip_required den Abstand zum zip_available berechnen und
  2. nach Entfernung sortieren Für jede zip_required die count mit range ermöglicht es Ihnen, wie Sie wissen, viele zip_availables sind im Radius dieser Entfernung.
  3. Filter (erster, wo COUNT (Orte)> N)

verwendeten I Beispieldaten zu erstellen:

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

Hinweis: Sie COUNT (Standorte) verwendet und SUM (Standorte) in Ihrem Frage: ich nahm an, es war COUNT (Standorte)

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 

Für jeden zip_required Dies wählt den minimalen Abstand, in die Nzip_available passen ‚s oder maximalen Abstand, wenn die Anzahl der zip_available‘ s kleiner als N.

+0

Ich denke, das ist in der Nähe. In Ihrem Beispiel ist rn nur die Rangfolge der Entfernung zwischen 2 Reißverschlüssen, geordnet nach der Entfernung. Was ich brauche, ist die Zipentfernung des letzten in dieser Liste, wobei die Summe seiner Orte plus alle vorherigen Orte größer oder gleich N ist. –

+0

@Josh: Dies wird die Entfernung des entferntesten Ortes mit dem nächsten N zurückgeben. Ist es nicht was willst du? – Quassnoi

+0

Limit 1 in einer Oracle-Abfrage? Ich habe etwas verpasst. – tuinstoel

1

ich das gleiche Problem gelöst, indem eine Teilmenge von ZIPs innerhalb eines quadratischen Radius von dem gegebenen Reißverschluss (leicht Mathematik: < oder> NSWE Radius) zu schaffen, dann iteratin g durch jeden Eintrag in der Teilmenge, um zu sehen, ob sie innerhalb des benötigten Radius war. Arbeitete wie ein Charme und war sehr schnell.

0

Ich hatte teilweise ähnliche Anforderungen in einem meiner alten Projekte ... um die Entfernung zwischen 2 Postleitzahlen in den USA zu berechnen. Um das Gleiche zu lösen, hatte ich die US-Geodaten in großem Umfang genutzt. Der Ansatz bestand im Wesentlichen darin, die Quellziffern (Breitengrad, Längengrad) und Zielziffern (Breitengrad, Längengrad) zu ermitteln. Nun hatte ich eine Funktion angewendet, um die Entfernung basierend auf dem obigen zu erhalten. Die Basisformel, die dabei hilft, diese Berechnung ist im following site ich auch das Ergebnis unter Bezugnahme auf this site validiert hatte ...

Hinweis: Dies wird jedoch ungefähre Entfernungen liefern, so dass man diese entsprechend nutzen kann. Vorteile sind einmal superschnell konstruiert, um die Ergebnisse zu holen.