2013/5/2 Moisés P. Sena <[email protected]>

> Bom dia pessoal,
>
> Tenho dados em uma tabela, e um campo de chave primaria que é um TIMESTAMP
> e preciso achar o mínimo diário da coluna VALOR e retornar o DATAHORA
> correspondente:
>
> create table dados (
>   datahora TIMESTAMP NOT NULL PRIMARY KEY,
>   valor INT
> );
>
> COPY dados (datahora, valor) FROM STDIN DELIMITER "|";
> 2013-01-01 00:00:00 | 2
> 2013-01-01 00:10:00 | 3
> 2013-01-01 00:20:00 | 1
> 2013-01-01 00:30:00 | 5
> 2013-01-01 00:40:00 | 7
> 2013-01-01 00:50:00 | 2
> 2013-01-02 00:00:00 | 4
> 2013-01-02 00:10:00 | 3
> 2013-01-02 00:20:00 | 7
> 2013-01-02 00:30:00 | 2
> 2013-01-02 00:40:00 | 5
> 2013-01-02 00:50:00 | 2
> \.
>
>
> Cada registro é inserido de 10 em 10 minutos, preciso mostrar a média de
> cada hora.
> Um intervalo de datas será definido posteriormente.
>
> *Primeiro resultado esperado:*
> *dia | datahora | valor_minimo*
> 2013-01-01 | 2013-01-01 00:20:00 | 1
> 2013-01-02 | 2013-01-02 00:30:00 | 2
>
> *OBS: *Observe que às 2013-01-02 00:30:00 e 2013-01-02 00:50:00 o valor
> se repete, neste caso, exibir apenas o de menor data.
>
>
Outra solução seria usando DISTINCT ON e WINDOW FUNCTION (first_value):

SELECT DISTINCT ON(datahora)
    datahora::date AS dia,
    first_value(datahora) OVER(PARTITION BY date_trunc('day', datahora)
ORDER BY valor, datahora) AS datahora,
    valor AS valor_minimo
FROM dados;


> *Segundo resultado esperado:*
> *dia | datahora | valor_minimo*
> 2013-01-01 | 2013-01-01 00:20:00 | 1
> 2013-01-02 | 2013-01-02 00:30:00 | 2
> 2013-01-02 | 2013-01-02 00:50:00 | 2
>
> *OBS: *Observe que às 2013-01-02 00:30:00 e 2013-01-02 00:50:00 o valor
> se repete, neste caso, exibir ambos ordenados pela DATAHORA.
>
> Alguma sugestão de como fazer isso direto no Postgres?
> Considerem que so tenho em maos o PSQL em um terminal Linux.
>
>
>
Podemos ainda usar a WINDOW FUNCTION e injetar numa sub-consulta:

SELECT dia, datahora, valor_minimo FROM (
    SELECT DISTINCT ON(datahora)
        datahora::date AS dia,
        datahora,
        first_value(valor) OVER(PARTITION BY date_trunc('day', datahora)
ORDER BY valor, datahora) AS valor_minimo,
        valor
    FROM dados
) AS a
WHERE a.valor = a.valor_minimo;

Se analisarmos somente os custos (EXPLAIN), essas opções foram mais
performáticas que as oferecidas anteriormente, mas tem-se que fazer uma
análise mais profunda para confirmar.

Atenciosamente,
-- 
Matheus de Oliveira
Analista de Banco de Dados
Dextra Sistemas - MPS.Br nível F!
www.dextra.com.br/postgres
_______________________________________________
pgbr-geral mailing list
[email protected]
https://listas.postgresql.org.br/cgi-bin/mailman/listinfo/pgbr-geral

Responder a