Pergunta

Dada uma função ZipDistance (ZipFrom, Zipto) que calcula a distância (em milhas) entre dois códigos postais e as seguintes tabelas:

create table zips_required(
   zip varchar2(5)
);

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

Como posso construir uma consulta que retorne a mim cada CEP da tabela zips_required e a distância mínima que produziria uma soma (locais)> = n.

Até agora, acabamos de executar uma consulta exaustiva de loop para cada raio até atendermos aos critérios.

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

Isso pode demorar um pouco em uma grande lista. Parece que isso pode ser feito com uma consulta analítica do Oracle ao longo das linhas de:

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

As únicas consultas analíticas que fiz foram "row_number sobre (partição por ordem por)" baseada, e estou passando por áreas desconhecidas com isso. Qualquer orientação sobre isso é muito apreciada.

Foi útil?

Solução

Isso é o que eu criei:

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. Para cada zip_required Calcule a distância para o zip_available e classificá -los à distância
  2. Para cada zip_required a count com range permite que você saiba quantos zip_availables estão no raio dessa distância.
  3. filtro (primeiro onde contagem (locais)> n)

Eu costumava criar dados de amostra:

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

Observação: Você usou a contagem (locais) e a soma (locais) em sua pergunta, presumi que era contagem (locais)

Outras dicas

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

Para cada zip_required, isso selecionará a distância mínima na qual o ajuste N zip_availableS, ou distância máxima se o número de zip_availableS é menor que N.

Resolvi o mesmo problema criando um subconjunto de ZIP dentro de um raio quadrado do zip fornecido (Matemática fácil: <ou> Radius), então iterando cada entrada no subconjunto para ver se estava dentro do raio necessário. Funcionou como um encanto e foi muito rápido.

Eu tinha requisitos parcialmente semelhantes em um dos meus projetos antigos ... para calcular a distância entre 2 códigos ZIPs nos EUA. Para resolver o mesmo, eu fiz um ótimo uso de dados espaciais dos EUA. Basicamente, a abordagem era obter o código ZIPCODE (latitude, longitude) e o ZipCode de destino (latitude, longitude). Agora então eu havia aplicado uma função para obter a distância com base no acima. A fórmula base que ajuda a fazer esse cálculo está disponível no A seguir, localEu também havia validado o resultado referindo -se a esse site...

Nota: No entanto, isso fornecerá distâncias aproximadas, para que se possa usá -lo de acordo. Os benefícios já foram construídos é super rápido para obter os resultados.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top