Pregunta

Muy bien, este problema es un poco complicado, así que tengan paciencia conmigo.

Tengo una tabla llena de datos. Una de las columnas de las tablas es una EntryDate. Puede haber múltiples entradas por día. Sin embargo, quiero seleccionar todas las filas que son la última entrada en sus respectivos días, y quiero seleccionar todas las columnas de dicha tabla.

Una de las columnas es una columna de identificador único, pero no es la clave principal (no tengo ni idea de por qué está ahí, lo que es un sistema bastante viejo). Para los propósitos de demostración, decir la tabla es el siguiente:

create table ExampleTable (
    ID int identity(1,1) not null,
    PersonID int not null,
    StoreID int not null,
    Data1 int not null,
    Data2 int not null,
    EntryDate datetime not null
)

La clave principal está en PersonaID y StoreID, que lógicamente define singularidad.

Ahora, como he dicho, quiero seleccionar todas las filas que son las últimas entradas en ese día en particular (para cada combinación Persona-tienda). Esto es bastante fácil:

--Figure 1
select PersonID, StoreID, max(EntryDate)
from ExampleTable
group by PersonID, StoreID, dbo.dayof(EntryDate)

Donde dbo.dayof () es una función simple que elimina la componente de tiempo a partir de una fecha y hora. Sin embargo, hacer esto pierde el resto de las columnas! No puedo simplemente incluir las otras columnas, porque entonces tendría que group by ellos, lo que produciría los resultados erróneos (especialmente desde que ID es único).

He encontrado un truco sucio que va a hacer lo que quiera, pero debe haber una mejor manera - aquí está mi solución actual:

select
    cast(null as int) as ID,
    PersonID,
    StoreID,
    cast(null as int) as Data1,
    cast(null as int) as Data2,
    max(EntryDate) as EntryDate
into #StagingTable
from ExampleTable
group by PersonID, StoreID, dbo.dayof(EntryDate)

update Target set
    ID = Source.ID,
    Data1 = Source.Data1,
    Data2 = Source.Data2,
from #StagingTable as Target
inner join ExampleTable as Source
    on Source.PersonID = Target.PersonID
   and Source.StoreID = Target.StoreID
   and Source.EntryDate = Target.EntryDate

Esto me pone los datos correctos en #StagingTable pero, bueno, mire! Crear una tabla con valores nulos, a continuación, haciendo una actualización para obtener los valores de nuevo - sin duda hay una mejor manera de hacer esto? Una sola instrucción que me llevará a todos los valores de la primera vez?

Es mi creencia de que la correcta combinación en que select originales (Figura 1) que hacer el truco, como un auto-unirse o algo ... pero ¿cómo se hace eso con la cláusula group by? No puedo encontrar la sintaxis correcta para hacer ejecutar la consulta.

Soy bastante nuevo con SQL, así que es probable que me falta algo obvio. ¿Alguna sugerencia?

(que trabaja en T-SQL, si hace alguna diferencia)

¿Fue útil?

Solución

No hay realmente manera "elegante". Cuando se tiene el grupo Agrupar por consultas de este tipo, que va a tener o sub-consultas o tablas temporales.

Esto funciona:

Select ID, A.PersonID, A.StoreID, Data1, Data2, A.EntryDate
From ExampleTable As A
Inner Join
    (select PersonID, StoreID, max(EntryDate) As EntryDate
    from ExampleTable
    group by PersonID, StoreID, dbo.dayof(EntryDate)) As B
  On ExampleTable.PersonID = B.PersonID 
    And ExampleTable.StoreID = B.StoreID 
    And ExampleTable.EntryDate = B.EntryDate

No debe ser demasiado abajo en la solución que se le ocurrió sin embargo. El uso de tablas temporales Nunca ve elegante, pero es eficiente; No me sorprendería si su solución original de dos etapas es más rápido que mi solución de un solo paso. (Que tendrá que probar para saber con seguridad.)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top