PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Application Rails 3 avec PostgreSQL - Obtenir la liste des messages regroupés par conversation

Si cela ne vous dérange pas de vous salir les mains avec un peu de SQL, vous pouvez utiliser un fonction de fenêtre pour faire le travail. Vous pouvez obtenir les identifiants de publication avec ce SQL :

select id
from (
    select id,
           rank() over (partition by thread_id order by created_at desc)
    from posts
    where receiver_id = #{user.id}
) as dt
where rank = 1

Si vous voulez plus de colonnes, ajoutez-les aux deux clauses SELECT. Le #{user.id} est, bien sûr, le destinataire qui vous intéresse.

La partie intéressante est la fonction fenêtre :

rank() over (partition by thread_id order by created_at desc)

Cela partitionnera la table en groupes basés sur thread_id (sorte de GROUP BY localisé), classez-les par horodatage (le plus récent en premier), puis rank() donne 1 pour la première entrée de chaque groupe, 2 pour la seconde, etc.

Soit un tableau qui ressemble à ceci :

=> select * from posts;
 id | receiver_id | thread_id |     created_at      
----+-------------+-----------+---------------------
  1 |           1 |         2 | 2011-01-01 00:00:00
  2 |           1 |         2 | 2011-02-01 00:00:00
  3 |           1 |         2 | 2011-03-01 00:00:00
  4 |           1 |         3 | 2011-01-01 00:00:00
  5 |           1 |         4 | 2011-01-01 00:00:00
  6 |           1 |         3 | 2011-01-01 13:00:00
  7 |           2 |        11 | 2011-06-06 11:23:42
(7 rows)

La requête interne vous donne ceci :

=> select id, rank() over (partition by thread_id order by created_at desc)
   from posts
   where receiver_id = 1;

 id | rank 
----+------
  3 |    1
  2 |    2
  1 |    3
  6 |    1
  4 |    2
  5 |    1
(6 rows)

Et puis nous enveloppons la requête externe autour de cela pour ne retirer que les correspondances les mieux classées :

=> select id
    from (                                                                  
        select id,
               rank() over (partition by thread_id order by created_at desc)
        from posts
        where receiver_id = 1
    ) as dt
    where rank = 1;

 id 
----
  3
  6
  5
(3 rows)

Alors ajoutez les colonnes supplémentaires que vous voulez et emballez le tout dans un Post.find_by_sql et vous avez terminé.