Très bien, ce problème est un peu compliqué, alors supportez-moi.Agrégat semi-complexe Sélectionnez déclaration confusion
J'ai une table pleine de données. Une des colonnes de la table est une EntryDate. Il peut y avoir plusieurs entrées par jour. Cependant, je veux sélectionner toutes les lignes qui sont la dernière entrée sur leurs jours respectifs, et je veux sélectionner toutes les colonnes de cette table.
Une des colonnes est une colonne d'identifiant unique, mais ce n'est pas la clé primaire (je ne sais pas pourquoi c'est là, c'est un système assez ancien). Aux fins de démonstration, par exemple la table ressemble à ceci:
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 clé primaire est PersonID et StoreID, qui définit logiquement l'unicité. Maintenant, comme je l'ai dit, je veux sélectionner toutes les lignes qui sont les dernières entrées ce jour-là (pour chaque combinaison Person-Store). Ceci est assez facile:
--Figure 1
select PersonID, StoreID, max(EntryDate)
from ExampleTable
group by PersonID, StoreID, dbo.dayof(EntryDate)
Où dbo.dayof() est une fonction simple que les bandes de la composante temporelle d'un datetime. Cependant, cela perd le reste des colonnes! Je ne peux pas simplement inclure les autres colonnes, car alors je devrais les group by
, ce qui produirait de mauvais résultats (d'autant plus que ID est unique).
J'ai trouvé une bidouille qui va faire ce que je veux, mais il doit y avoir une meilleure façon - voici ma solution actuelle:
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
Cela me récupère les données correctes dans #StagingTable
mais, eh bien, Regarde ça! Créer une table avec des valeurs nulles, puis faire une mise à jour pour récupérer les valeurs - il y a sûrement une meilleure façon de faire cela? Une déclaration unique qui va me donner toutes les valeurs la première fois?
Je crois que la jointure correcte sur ce select
original (figure 1) ferait l'affaire, comme une auto-jointure ou quelque chose ... mais comment faites-vous cela avec la clause group by
? Je ne trouve pas la bonne syntaxe pour exécuter la requête. Je suis assez nouveau avec SQL, il est donc probable que je manque quelque chose d'évident. Aucune suggestion?
(Travailler dans T-SQL, si cela fait une différence)
Merci pour le heads up sur la performance. Je l'ai essayé dans les deux sens, et vous avez raison - la méthode de table de temp a terminé 1 seconde plus vite (83 vs 84 secondes au total)! Mais je vais prendre la concision de votre solution sur ce coup de pouce (presque) n'importe quel jour ... –