Аналитический вопрос Oracle - PullRequest
6 голосов
/ 23 июня 2009

Дана функция zipdistance (zipfrom, zipto), которая вычисляет расстояние (в милях) между двумя почтовыми индексами и следующими таблицами:

create table zips_required(
   zip varchar2(5)
);

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

Как я могу построить запрос, который будет возвращать мне каждый почтовый индекс из таблицы zips_required и минимальное расстояние, на котором можно получить сумму (местоположения)> = n.

До сих пор мы просто выполняли исчерпывающий цикл запросов для каждого радиуса, пока не выполнили критерии.

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

Это может занять некоторое время в большом списке. Такое ощущение, что это может быть сделано с помощью аналитического запроса оракула в следующем виде:

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

Единственные аналитические запросы, которые я сделал, были основаны на "row_number over (split by order by)", и с этим я ступаю в неизвестные области. Любое руководство по этому вопросу высоко ценится.

Ответы [ 4 ]

2 голосов
/ 24 июня 2009

Вот что я придумал:

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. Для каждого zip_required рассчитайте расстояние до zip_available и отсортируйте их по расстоянию
  2. Для каждого zip_required count с range позволяет узнать, сколько zip_availables находится в радиусе этого расстояния.
  3. фильтр (первый, где COUNT (местоположение)> N)

Я использовал для создания образцов данных:

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

Примечание: вы использовали COUNT (местоположения) и SUM (местоположения) в своем вопросе, я предположил, что это было COUNT (местоположения)

1 голос
/ 28 июня 2009

Я решил ту же проблему, создав подмножество ZIP в квадратном радиусе от заданного почтового индекса (easy math: <или> NSWE radius), затем перебирая каждую запись в подмножестве, чтобы увидеть, находится ли она в нужном радиусе , Работал как шарм и был очень быстрым.

1 голос
/ 23 июня 2009
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

Для каждого zip_required будет выбрано минимальное расстояние, в которое вписывается N zip_available, или максимальное расстояние, если число zip_available меньше N.

0 голосов
/ 10 августа 2012

У меня были частично аналогичные требования в одном из моих старых проектов ... для расчета расстояния между двумя почтовыми индексами в США. Чтобы решить то же самое, я широко использовал пространственные данные США. В основном подход заключался в получении исходного почтового индекса (широта, долгота) и целевого почтового индекса (широта, долгота). Теперь я применил функцию, чтобы получить расстояние на основе вышеизложенного. Базовая формула, которая помогает в этом расчете, доступна на сайте Я также подтвердил результат, ссылаясь на этот сайт ...

Примечание: однако это даст приблизительные расстояния, поэтому можно использовать это соответственно. Преимущества когда-то построены так быстро, чтобы получить результаты.

...