2012/12/6 Thiago <zan...@farmaponte.com.br>

> On 05/12/2012 17:16, Matheus de Oliveira wrote:
> >
> >
> > 2012/12/5 Thiago <zan...@farmaponte.com.br
> > <mailto:zan...@farmaponte.com.br>>
> >
> >     Boa tarde.
> >
> >     Tenho as seguintes tabelas:
> >
> >     tb_mensagem
> >         id
> >         id_mensagem_pai
> >         dth_insert
> >
> >     tb_mensagem_leitura
> >         id_mensagem
> >         dth_insert
> >
> >     A tabela de mensagens, sempre que existe uma mensagem com
> >     id_mensagem_pai, significa que é uma resposta, as mensagens originais
> >     (primeiras) contém 0 (zero) no campo id_mensagem_pai.
> >
> >     Na tabela tb_mensagem_leitura eu tenho um histórico de todas as vezes
> >     que o usuário leu a mensagem, sendo gravado no campo id_mensagem
> dessa
> >     tabela sempre o id da mensagem original.
> >
> >     Preciso identificar quantas mensagens não lidas existe na para o
> >     usuário, sendo que uma mensagem não lida é:
> >     1) sem registro na tabela tb_mensagem_leitura;
> >     2) o registro da tabela tb_mensagem_leitura é com data menor que a
> >     última resposta da mensagem original.
> >
> >     Alguém poderia me ajudar com este select? Ou até mesmo com a forma em
> >     que estruturei as tabelas, pois para chegar neste resultado está um
> >     pouco complicado.
> >
> >
> > Cara, se eu não boiei na maionese, a consulta abaixo resolve o seu
> > problema (não testado):
> >
> > WITH RECURSIVE mensagens AS (
> >      SELECT id AS id_original, id, dth_insert
> >      FROM tb_mensagem
> >      WHERE id_mensagem_pai = 0
> >      UNION ALL
> >      SELECT pai.id_original, filha.id <http://filha.id>,
> filha.dth_insert
> >      FROM tb_mensagem AS filha
> >          INNER JOIN mensagens AS pai ON pai.id <http://pai.id> =
> > filha.id_mensagem_pai
> > ), ultimas AS (
> >      SELECT m.id_original, MAX(m.dth_insert) AS dth_insert
> >      FROM mensagens AS m
> >      GROUP BY m.id_original
> > )
> > SELECT COUNT(*)
> > FROM ultimas AS u
> >      LEFT JOIN tb_mensagem_leitura AS l
> >          ON l.id_mensagem = u.id_original
> > WHERE l.id_mensagem IS NULL OR l.dth_insert < u.dth_insert;
> >
> >
> > Não me parece muito performático, uma forma de melhorar seria SEMPRE
> > guardar o id da mensagem original em tb_mensagem (não só a da pai, mas a
> > da primeira na hierarquia), o que evitaria toda essa sobrecarga da query
> > recursiva e da outra sub-query, que na prática só estão pegando a data
> > da última mensagem.
> >
> > Atenciosamente,
>
> Mateus, muito obrigado pela resposta.
>
> Acho que não expliquei direito.


Também acho... =P


> Na tabela tb_mensagem, o campo
> id_mensagem_pai é sempre o id da mensagem original. Todas as respostas
> estão amarradas a uma única mensagem e não em um formato de árvore.
>
>
Agora entendi, é mais simples então.


Dessa forma você acha que existe uma solução melhor com uma melhor
> performance? Essa será uma leitura muitas vezes executada, pois cada
> página do portal que o usuário acessa essa consulta é refeita para
> atualizar as mensagens não lidas.
>
>
>
Sim. A forma abaixo:

 SELECT COUNT(*) FROM (
    SELECT
        CASE m.id_mensagem_pai WHEN 0 THEN m.id ELSE m.id_mensagem_pai END
AS id_original,
        MAX(m.dth_insert) AS dth_insert
    FROM tb_mensagem AS m
    GROUP BY CASE m.id_mensagem_pai WHEN 0 THEN m.id ELSE m.id_mensagem_pai
END
) AS u
    LEFT JOIN tb_mensagem_leitura AS l
        ON l.id_mensagem = u.id_original
WHERE l.id_mensagem IS NULL OR l.dth_insert < u.dth_insert;

Eu modelaria na mensagem original o id_mensagem_pai = id ao invés de 0 na
mensagem original, assim tira esse CASE daí.

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

Responder a