Consigue la primera fila de cada grupo

Resuelto kazinix asked hace 13 años • 19 respuestas

Tengo una tabla en la que quiero obtener la última entrada para cada grupo. Aquí está la tabla:

DocumentStatusLogsMesa

IDENTIFICACIÓN ID del documento Estado Fecha de creacion
2 1 T1 29/07/2011
3 1 T2 30/07/2011
6 1 T1 8/02/2011
1 2 T1 28/07/2011
4 2 T2 30/07/2011
5 2 T3 01/08/2011
6 3 T1 8/02/2011

La tabla se agrupará DocumentIDy ordenará DateCreateden orden descendente. Para cada uno DocumentID, quiero obtener el estado más reciente.

Mi salida preferida:

ID del documento Estado Fecha de creacion
1 T1 8/02/2011
2 T3 01/08/2011
3 T1 8/02/2011
  • ¿Existe alguna función agregada para obtener solo los mejores de cada grupo? Vea el pseudocódigo GetOnlyTheTopa continuación:

      SELECT
        DocumentID,
        GetOnlyTheTop(Status),
        GetOnlyTheTop(DateCreated)
      FROM DocumentStatusLogs
      GROUP BY DocumentID
      ORDER BY DateCreated DESC
    
  • Si dicha función no existe, ¿hay alguna manera de lograr el resultado que deseo?

  • O, en primer lugar, ¿podría esto deberse a una base de datos no normalizada? Estoy pensando, dado que lo que estoy buscando es solo una fila, ¿debería statusestar ubicada también en la tabla principal?

Consulte la tabla principal para obtener más información:

DocumentsTabla actual

ID del documento Título Contenido Fecha de creacion
1 TítuloA ... ...
2 TítuloB ... ...
3 TítuloC ... ...

¿La tabla principal debería ser así para poder acceder fácilmente a su estado?

ID del documento Título Contenido Fecha de creacion Estado actual
1 TítuloA ... ... s1
2 TítuloB ... ... s3
3 TítuloC ... ... s1

ACTUALIZACIÓN Acabo de aprender a utilizar "aplicar", lo que facilita la solución de estos problemas.

kazinix avatar Jul 27 '11 15:07 kazinix
Aceptado
;WITH cte AS
(
   SELECT *,
         ROW_NUMBER() OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC) AS rn
   FROM DocumentStatusLogs
)
SELECT *
FROM cte
WHERE rn = 1

Si espera 2 entradas por día, entonces elegirá una arbitrariamente. Para obtener ambas entradas para un día, use DENSE_RANK en su lugar

En cuanto a normalizado o no, depende si quieres:

  • mantener el estado en 2 lugares
  • preservar el historial de estado
  • ...

Tal como está, conserva el historial de estado. Si también desea el estado más reciente en la tabla principal (que es desnormalización), necesitará un disparador para mantener el "estado" en la tabla principal. o elimine esta tabla de historial de estado.

gbn avatar Jul 27 '2011 08:07 gbn

Acabo de aprender a usarlo cross apply. A continuación se explica cómo usarlo en este escenario:

 select d.DocumentID, ds.Status, ds.DateCreated 
 from Documents as d 
 cross apply 
     (select top 1 Status, DateCreated
      from DocumentStatusLogs 
      where DocumentID = d.DocumentId
      order by DateCreated desc) as ds
kazinix avatar Aug 30 '2012 06:08 kazinix

Sé que este es un hilo antiguo, pero las TOP 1 WITH TIESsoluciones son bastante buenas y pueden ser útiles para leerlas.

select top 1 with ties
   DocumentID
  ,Status
  ,DateCreated
from DocumentStatusLogs
order by row_number() over (partition by DocumentID order by DateCreated desc)

La select top 1 with tiescláusula le dice a SQL Server que desea devolver la primera fila por grupo. Pero, ¿cómo sabe SQL Server cómo agrupar los datos? Aquí es donde order by row_number() over (partition by DocumentID order by DateCreated descentra en juego. La columna/columnas posteriores partition bydefinen cómo SQL Server agrupa los datos. Dentro de cada grupo, las filas se ordenarán según las order bycolumnas. Una vez ordenado, la fila superior de cada grupo se devolverá en la consulta.

Puede encontrar más información sobre la cláusula TOP aquí .

Josh Gilfillan avatar Jan 24 '2018 00:01 Josh Gilfillan