Аналитический вопрос Oracle
-
06-07-2019 - |
Вопрос
Имеется функция 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 (разбить по порядку на) " основанный, и я ступаю в неизвестные области с этим. Любое руководство по этому вопросу высоко ценится.
Решение
Это то, что я придумал:
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
<Ол>
zip_required
рассчитайте расстояние до zip_available
и отсортируйте их по расстоянию count
range
с zip_availables
вы можете узнать, сколько <=> находится в радиусе этого расстояния. Я использовал для создания образцов данных:
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 (местоположения)
Другие советы
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 в квадратном радиусе от заданного почтового индекса (легкая математика: < или > радиус NSWE), затем перебирая каждую запись в подмножестве, чтобы посмотрите, был ли он в пределах необходимого радиуса. Работал как шарм и был очень быстрым. Р>
У меня были частично аналогичные требования в одном из моих старых проектов ... для расчета расстояния между двумя почтовыми индексами в США. Чтобы решить то же самое, я широко использовал пространственные данные США. В основном подход заключался в получении исходного почтового индекса (широта, долгота) и целевого почтового индекса (широта, долгота). Теперь я применил функцию, чтобы получить расстояние на основе вышеизложенного. Базовая формула, которая помогает выполнить этот расчет, доступна на следующем сайте . Я также подтвердил результат, сославшись на этот сайт ... р>
Примечание. Однако это даст приблизительное расстояние, поэтому можно использовать его соответствующим образом. Преимущества когда-то построены так быстро, чтобы получить результаты. Р>