Comment obtenir le dernier enregistrement par groupe dans SQL
Je suis confronté à un problème plutôt intéressant. J'ai une table avec la structure suivante:
CREATE TABLE [dbo].[Event]
(
Id int IDENTITY(1,1) NOT NULL,
ApplicationId nvarchar(32) NOT NULL,
Name nvarchar(128) NOT NULL,
Description nvarchar(256) NULL,
Date nvarchar(16) NOT NULL,
Time nvarchar(16) NOT NULL,
EventType nvarchar(16) NOT NULL,
CONSTRAINT Event_PK PRIMARY KEY CLUSTERED ( Id ) WITH (
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON
)
)
Donc, le problème est que je dois afficher ces données dans une grille. Il y a deux exigences. Le premier est d'afficher tous les événements, quelle que soit l'application qui les a lancés. C'est simple - une instruction select fera le travail très facilement.
La deuxième exigence est de pouvoir regrouper les événements par Application
. En d'autres termes, afficher tous les événements d'une manière que si le ApplicationId
est répété plus d'une fois, prenez seulement la dernière entrée pour chaque application. La clé primaire de l'Événement (Id) à ce stade, n'est plus nécessaire à cette requête.
Vous pouvez également remarquer que la Date et L'Heure de l'événement sont au format de chaîne. C'est ok car ils suivent les formats de date et d'heure standard: MM / JJ/AAAA et hh: mm: SS. Je peux les tirer comme suit:
Convert( DateTime, (Date + ' ' + Time)) AS 'TimeStamp'
Mon problème est que si j'utilise des fonctions D'agrégation sur le reste des colonnes, Je ne sais pas comment le feraient-elles se comporter:
SELECT
ApplicationId,
MAX(Name),
MAX(Description),
MAX( CONVERT(DateTime, (Date + ' ' + Time))) AS 'TimeStamp',
MAX( EventType )
FROM
Event
GROUP BY
ApplicationId
La raison pour laquelle j'hésite à le faire parce qu'une fonction telle que MAX
qui retourne la plus grande valeur pour une colonne donnée à partir d'une (sous -) ensemble d'enregistrements. Il ne faut pas tirer le dernier enregistrement!
Des idées sur la façon de sélectionner uniquement le dernier enregistrement sur une base par application?
8 réponses
Vous pouvez utiliser une fonction de classement et une expression de table commune .
WITH e AS
(
SELECT *,
ROW_NUMBER() OVER
(
PARTITION BY ApplicationId
ORDER BY CONVERT(datetime, [Date], 101) DESC, [Time] DESC
) AS Recency
FROM [Event]
)
SELECT *
FROM e
WHERE Recency = 1
Depuis SQL Server 2012, vous pouvez simplement
SELECT
[Month]
, [First] = FIRST_VALUE(SUM([Clicks])) OVER (ORDER BY [Month])
, [Last] = FIRST_VALUE(SUM([Clicks])) OVER (ORDER BY [Month] DESC)
FROM
[dbo].[Table]
GROUP BY [Month]
ORDER BY [Month]
SELECT
E.ApplicationId,
E.Name,
E.Description,
CONVERT(DateTime, (E.Date + ' ' + E.Time)) AS 'TimeStamp',
E.EventType
FROM
Event E
JOIN (SELECT ApplicationId,
MAX(CONVERT(DateTime, (Date + ' ' + Time))) AS max_date
FROM Event
GROUP BY ApplicationId) EM
on EM.ApplicationId = E.ApplicationId
and EM.max_date = CONVERT(DateTime, (E.Date + ' ' + E.Time)))
Vous pouvez utiliser une sous-requête ou une table CTE pour ce faire:
;WITH CTE_LatestEvents as (
SELECT
ApplicationId,
MAX( CONVERT(DateTime, (Date + ' ' + Time))) AS 'LatestTimeStamp',
FROM
Event
GROUP BY
ApplicationId
)
SELECT
ApplicationId,
Name,
Description,
CONVERT(DateTime, (Date + ' ' + Time))) AS 'TimeStamp',
EventType
FROM
Event e
Join CTE_LatestEvents le
on e.applicationid = le.applicationid
and CONVERT(DateTime, (e.Date + ' ' + e.Time))) = le.LatestTimeStamp
Parce que vous n'avez pas de clause where, le sous-ensemble des enregistrements est tous les enregistrements. Mais vous mettez max sur la mauvaise colonne(s) je pense. Cette requête vous donnera ce que vous cherchez.
Select max(applicationid), name, description, CONVERT(DateTime, (Date + ' ' + Time))
from event
group by name, description, CONVERT(DateTime, (Date + ' ' + Time))
Vous pouvez utiliser une sous-requête avec le groupe par le groupe en argument n'a pas besoin d'être dans la sélection. Cela suppose que Id est une auto incrémentée de sorte que le plus grand est le plus récent.
SELECT
ApplicationId,
Name,
Description,
CONVERT(DateTime, (Date + ' ' + Time)) AS 'TimeStamp',
EventType
FROM
Event e
WHERE
Id in (select max(Id) from Event GROUP BY ApplicationId)
Je pense que cela fonctionnera pour beaucoup de gens prêts à récupérer le dernier enregistrement inséré et il devrait être group by:
Select * from (select * from TableName ORDER BY id DESC) AS X GROUP BY FieldName
Cela fonctionnera pour ce qui suit:
Structure Du Tableau Nom de l'ID d'État 1 Junaid Oui 2 Jawad Non 3 Fahad Oui 4 Junaid Pas 5 Kashif Oui
Résultats Après La Requête Ci-Dessus Nom de l'ID d'État 4 Junaid Pas 2 Jawad Non 3 Fahad Oui 4 Kashif Oui
Il résulte simplement le dernier enregistrement de group by names.
Après 6 ans, une autre réponse pour SQL Server:
select t1.[Id], t2.[Value]
from [dbo].[Table] t1
outer apply (
select top 1 [Value]
from [dbo].[Table] t2
where t2.[Month]=t1.[Month]
order by [dbo].[Date] desc
)
Bien que J'aime beaucoup mieux la solution Postgresql avec sa fonctionnalité distincte on qui est plus agréable à taper et beaucoup plus efficace:
select distinct on (id),val
from tbl
order by id,val