AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 57610
Accepted
oxfist
oxfist
Asked: 2014-01-28 04:07:20 +0800 CST2014-01-28 04:07:20 +0800 CST 2014-01-28 04:07:20 +0800 CST

Como retornar corretamente um resultado de consulta apenas se não for NULL?

  • 772

Estou escrevendo uma função PL/pgSQL que cria um cursor para uma consulta que preciso verificar se ela retorna algo.

O que estou fazendo é isso:

  1. Execute a consulta
  2. Verifique se ele retorna algo.
  3. Caso contrário, duplique um parâmetro e execute a consulta novamente.
  4. Caso contrário, retorne todas as linhas da consulta.

Achei que verificar se a consulta retornava algo com um cursor era a melhor escolha, pois é uma consulta muito longa (juntando 5 tabelas e muitas colunas) e SELECT ... INTOnão parecia certo, porque eu teria que criar uma TYPEvez que o consulta tem colunas de uma tabela e uma coluna para um cálculo de distância.

O problema é que atualmente estou usando o cursor apenas para verificar se a consulta retornou algo dentro de um loop onde eu abro e fecho. Depois que a consulta retorna algo, saio do loop e retorno a consulta. Eu posso dizer imediatamente que esta é uma solução feia para o que eu preciso. Talvez alguém possa me ajudar com esta questão.

Aqui está um código que mostra o que estou fazendo atualmente.

CREATE FUNCTION store_distance(
    latitude double precision,
    longitude double precision,
    radius double precision,
    tries integer
)
RETURNS TABLE(
    store_id store.id%type,
    store_name store.name%type,
    distance double precision
)
AS
$$
DECLARE
    cur_stores CURSOR FOR
        SELECT
            store.id,
            store.name,
            get_distance(latitude, longitude, store.latitude, store.longitude) distance
        FROM
            store
        WHERE
            store.latitude BETWEEN (latitude - radius) AND (latitude + radius)
            AND store.longitude BETWEEN (longitude - radius) AND (longitude + radius)
        ORDER BY
            distance ASC;
    count int := 0;
    storerow RECORD;
BEGIN
    LOOP
        IF count = tries THEN
            EXIT;
        END IF;
        OPEN cur_stores;
        FETCH cur_stores INTO storerow;
        IF FOUND THEN
            EXIT;
        END IF;
        radius := radius * 2;
        count := count + 1;
        CLOSE cur_stores;
    END LOOP;
    RETURN QUERY
    SELECT
        store.id,
        store.name,
        get_distance(latitude, longitude, store.latitude, store.longitude) distance
    FROM
        store
    WHERE
        store.latitude BETWEEN (latitude - radius) AND (latitude + radius)
        AND store.longitude BETWEEN (longitude - radius) AND (longitude + radius)
    ORDER BY
        distance ASC;
END;
$$ LANGUAGE PLPGSQL;

Portanto, meu objetivo é fornecer coordenadas, raio e número de tentativas e tentar encontrar lojas nessa caixa de pesquisa. Se nenhuma loja for encontrada, dobro o raio e tento novamente até que algo seja retornado pela consulta ou até que o número de tentativas seja atingido.
A RETURN TABLEparte é basicamente porque quero voltar a distância, então RETURN SETOF storenão adiantou.

postgresql performance
  • 1 1 respostas
  • 3351 Views

1 respostas

  • Voted
  1. Best Answer
    Erwin Brandstetter
    2014-02-04T18:26:30+08:002014-02-04T18:26:30+08:00

    Eu não acho que você precisa de um cursor aqui. Para encurtar seu código, você pode usar apenas uma visualização. Para melhorar o desempenho, uma visualização materializada deve levá-lo mais longe. O Postgres 9.3 possui recursos integrados, mas você mesmo pode implementá-lo facilmente em versões mais antigas.

    Considere esta forma simplificada:

    CREATE FUNCTION store_distance(_lat    double precision
                                  ,_long   double precision
                                  ,_radius double precision
                                  ,_tries  integer)
    RETURNS TABLE(
       store_id   store.id%type
      ,store_name store.name%type
      ,distance   double precision) AS
    $func$
    DECLARE
       _ct  int   := 0;
       _pos point := point(_lat, _long);
    BEGIN
       LOOP
          EXIT WHEN _ct >= _tries
               OR   EXISTS (
                SELECT 1 FROM store s
                WHERE  point(s.latitude, s.longitude) <@ circle(_pos, _radius));
    
          _radius := _radius * 2;
          _ct     := _ct + 1;
       END LOOP;
    
       RETURN QUERY
       SELECT s.id, s.name
             ,get_distance(_lat, _long, s.latitude, s.longitude)
       FROM   store s
       WHERE  point(s.latitude, s.longitude) <@ circle(_pos, _radius);
       ORDER  BY 3;
    END
    $func$ LANGUAGE plpgsql STRICT;
    

    Fiz a função STRICTpara desabilitar a entrada NULL, o que poderia resultar em um loop infinito.

    Observe como eu uso círculos com o operador "Contained" em<@ vez de caixas . Pode-se supor que os cálculos sejam um pouco mais caros do que com caixas, mas isso dificilmente importa quando você suporta sua consulta com um índice GiST como:

    CREATE INDEX store_point_gist_idx ON store
    USING gist (point(latitude, longitude));
    

    Você pode considerar armazenar lat / lon pointpara começar e substituir o índice em uma expressão por um mais simples na coluna. Funciona de qualquer maneira, apenas certifique-se de que a consulta corresponda ao índice para que seja usado. Grande diferença para grandes mesas.

    Você pode estar interessado nesta resposta intimamente relacionada ao SO que postei no ano passado - com muito mais explicações e links.

    • 5

relate perguntas

  • Sequências Biológicas do UniProt no PostgreSQL

  • Como determinar se um Índice é necessário ou necessário

  • Onde posso encontrar o log lento do mysql?

  • Como posso otimizar um mysqldump de um banco de dados grande?

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve