Domanda

Bene, questo problema è un po 'complicato, in modo da portare con me.

Ho una tabella completa di dati. Una delle colonne della tabella è un EntryDate. Non ci può essere più voci al giorno. Tuttavia, voglio per selezionare tutte le righe che sono la voce più recente sui rispettivi giorni, e voglio selezionare tutte le colonne della stessa tabella.

Una delle colonne è una colonna identificatore univoco, ma non è la chiave primaria (non ho idea del perché è lì, questo è un sistema piuttosto vecchio). Ai fini della dimostrazione, dire che il tavolo è simile al seguente:

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 chiave primaria è PersonID e StoreID, che definisce logicamente unicità.

Ora, come ho detto, voglio selezionare tutte le righe che sono le ultime entrate in quel particolare giorno (per ogni combinazione Person-Store). Questo è abbastanza facile:

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

Dove dbo.dayof () è una funzione semplice che spoglia il componente temporale da un datetime. Tuttavia, facendo questo perde il resto delle colonne! Non posso semplicemente includere le altre colonne, perché poi avrei dovuto group by loro, che produce i risultati errati (soprattutto perché ID è unico).

Ho trovato un hack sporco che farà quello che voglio, ma ci deve essere un modo migliore - ecco la mia soluzione attuale:

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

Questo mi ottiene i dati corretti in #StagingTable ma, beh, un'occhiata! Creazione di una tabella con i valori nulli, poi facendo un aggiornamento per ottenere i valori di nuovo - sicuramente c'è un modo migliore per fare questo? Una singola istruzione che otterrà me tutti i valori per la prima volta?

E 'mia convinzione che la corretta join su quel select originale (Figura 1) farebbe il trucco, come un self-join o qualcosa del genere ... ma come si fa a farlo con la clausola group by? Non riesco a trovare la giusta sintassi per rendere la query eseguire.

Sono abbastanza nuovo con SQL, quindi è probabile che mi manca qualcosa di ovvio. Qualche suggerimento?

(Lavorare in T-SQL, se fa alcuna differenza)

È stato utile?

Soluzione

Non c'è davvero modo "elegante". Quando si dispone di gruppo Raggruppa per query come questo, si sta andando ad avere entrambi i sub-query o le tabelle temporanee.

Questo funziona:

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

Non dovrebbe essere troppo in basso sulla soluzione si avvicinò con però. Usando le tabelle temporanee mai Look elegante, ma è efficace; Non sarei sorpreso se la soluzione originale in due fasi è effettivamente più veloce rispetto al mio soluzione di uno stadio. (Dovrete mettere alla prova per sapere con certezza.)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top