sql >> Base de Datos >  >> RDS >> PostgreSQL

Aplicación Rails 3 con PostgreSQL:obtener la lista de mensajes agrupados por estación de conversación

Si no le importa ensuciarse las manos con un poco de SQL, puede usar un función de ventana para hacer el trabajo. Puede obtener los ID de publicación con este 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 desea más columnas, agréguelas a ambas cláusulas SELECT. El #{user.id} es, por supuesto, el destinatario que le interesa.

La parte interesante es la función de ventana:

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

Esto dividirá la tabla en grupos según thread_id (una especie de GRUPO POR localizado), ordénelos por la marca de tiempo (los más recientes primero) y luego rank() da 1 para la primera entrada de cada grupo, 2 para la segunda, etc.

Dada una tabla que se ve así:

=> 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 consulta interna te da esto:

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

Y luego envolvemos la consulta externa para eliminar solo las coincidencias de clasificación superior:

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

Así que agregue las columnas adicionales que desee y envuélvalo todo en un Post.find_by_sql y listo.