2009-06-23 15 views
6

Biorąc funkcją zipdistance (zipfrom, zipto), który oblicza odległość (w milach) pomiędzy dwoma kody pocztowe i poniższych tabelach:Oracle Analityczne Pytanie

create table zips_required(
    zip varchar2(5) 
); 

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

Jak można skonstruować kwerendę, która będzie zwracać się do mnie każdy kod pocztowy z tabeli zips_required i minimalna odległość, która wytworzy sumę (lokalizacje)> = n.

Do tej pory przeprowadziliśmy wyczerpującą analizę pętli dla każdego promienia, dopóki nie spełnimy kryteriów.

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

Może to chwilę potrwać na dużej liście. Czuje się jak można to zrobić z wyrocznią analitycznej zapytania wzdłuż linii:

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

Jedyne analitycznych zapytań I zrobili zostały „row_number nad (partycję)” zamówienia przez w oparciu, a ja kroczenie w nieznane obszary. Wszelkie wskazówki na ten temat są bardzo doceniane.

Odpowiedz

2

To właśnie wymyśliłem:

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. Dla każdego zip_required obliczyć odległość do zip_available i sortować je według odległości
  2. Dla każdego zip_requiredcount z range pozwala wiedzieć, w jaki sposób wiele zip_availables znajduje się w promieniu tej odległości.
  3. filtr (pierwsza gdzie COUNT (lokalizacje)> N)

I wykorzystywane do tworzenia przykładowych danych:

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

Uwaga: użyłeś count (lokalizacje) oraz suma (lokalizacje) w swojej pytanie, założyłem, że to COUNT (lokalizacje)

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 

Dla każdego zip_required tego wybierze minimalną odległość, w których pracują Nzip_available "S lub maksymalnej odległości, jeżeli liczba zip_available jest mniej niż N.

+0

Myślę, że jest blisko. W twoim przykładzie, rn będzie po prostu rankingiem odległości między 2 zamkami zamawianymi przez odległość. Potrzebuję tylko zipdistance ostatniego z tej listy, którego suma lokalizacji plus wszystkie poprzednie lokalizacje jest większa lub równa N. –

+0

@ Jos: to zwróci odległość najdalszej lokalizacji z najbliższą N. Czy tego nie chcesz? – Quassnoi

+0

limit 1 w zapytaniu Oracle? Coś przeoczyłem. – tuinstoel

1

Rozwiązałem ten sam problem, tworząc podzestaw ZIP w promieniu kwadratu od podanego suwaka (łatwa matematyka: < lub> promień NSWE), a następnie iteratyna g poprzez każdy wpis w podzbiorze, aby sprawdzić, czy znajdował się w wymaganym promieniu. Pracował jak urok i był bardzo szybki.

0

Miałem częściowo podobne wymagania w jednym z moich starych projektów ... aby obliczyć odległość między 2 kodami zip w USA. Aby rozwiązać ten problem, świetnie wykorzystałem US Spatial Data. Zasadniczo podejście polegało na uzyskaniu kodu źródłowego kodu pocztowego (szerokość geograficzna, długość geograficzna) i docelowego kodu pocztowego (szerokość geograficzna, długość geograficzna). Teraz zastosowałem funkcję, aby uzyskać odległość na podstawie powyższego. Formuła bazowa, która pomaga w czynieniu tego obliczenia jest dostępny w following site ja również potwierdzone przez wyniki odnoszące się do this site ...

Uwaga: Jednak to zapewni przybliżone odległości, więc można to wykorzystać odpowiednio. Korzyści są raz skonstruowane superszybkie, aby pobrać wyniki.