web-dev-qa-db-fra.com

Comment interroger SQL pour une date d'enregistrement la plus récente pour chaque utilisateur?

J'ai une table qui est une collection d'entrées à quand un utilisateur a été connecté.

username, date,      value
--------------------------
brad,     1/2/2010,  1.1
fred,     1/3/2010,  1.0
bob,      8/4/2009,  1.5
brad,     2/2/2010,  1.2
fred,     12/2/2009, 1.3

etc..

Comment créer une requête qui me donnerait la date la plus récente pour chaque utilisateur?

Mise à jour: J'ai oublié qu'il me fallait une valeur correspondant à la date la plus récente.

180
fishhead
select t.username, t.date, t.value
from MyTable t
inner join (
    select username, max(date) as MaxDate
    from MyTable
    group by username
) tm on t.username = tm.username and t.date = tm.MaxDate
311
RedFilter

Utilisation des fonctions de fenêtre (fonctionne avec Oracle, Postgres 8.4, SQL Server 2005, DB2, Sybase, Firebird 3.0, MariaDB 10.3)

select * from (
    select
        username,
        date,
        value,
        row_number() over(partition by username order by date desc) as rn
    from
        yourtable
) t
where t.rn = 1
90
dotjoe

Je constate que la plupart des développeurs utilisent une requête en ligne sans tenir compte de son impact sur des données volumineuses.

Vous pouvez y parvenir simplement en:

SELECT a.username, a.date, a.value
FROM myTable a
LEFT OUTER JOIN myTable b
ON a.username = b.username 
AND a.date < b.date
WHERE b.username IS NULL
ORDER BY a.date desc;
37
sujeet

Pour obtenir la ligne entière contenant la date maximum pour l'utilisateur:

select username, date, value
from tablename where (username, date) in (
    select username, max(date) as date
    from tablename
    group by username
)
19
Alison R.
SELECT *     
FROM MyTable T1    
WHERE date = (
   SELECT max(date)
   FROM MyTable T2
   WHERE T1.username=T2.username
)
7
Manix

Celui-ci devrait vous donner le résultat correct pour votre question modifiée.

La sous-requête veille à ne rechercher que les lignes de la date la plus récente, et le GROUP BY extérieur prendra soin des liens. Quand il y a deux entrées pour la même date pour le même utilisateur, elle retournera celle avec le plus haut value.

SELECT t.username, t.date, MAX( t.value ) value
FROM your_table t
JOIN (
       SELECT username, MAX( date ) date
       FROM your_table
       GROUP BY username
) x ON ( x.username = t.username AND x.date = t.date )
GROUP BY t.username, t.date
2
Peter Lang

D'après mon expérience, le moyen le plus rapide est de prendre chaque ligne pour laquelle il n'y a pas de nouvelle ligne dans la table. Voici un petit repère avec certaines données que j'ai sous la main.

Un autre avantage est que la syntaxe utilisée est très simple et que la signification de la requête est assez facile à comprendre (prenez toutes les lignes de sorte qu'aucune nouvelle ligne n'existe pour le nom d'utilisateur considéré).

N'EXISTE PAS

SELECT username, value
FROM t
WHERE NOT EXISTS (
  SELECT *
  FROM t AS witness
  WHERE witness.date > t.date
);

Expliquez le coût total: 2.38136

ROW_NUMBER

SELECT username, value
FROM (
  SELECT username, value, row_number() OVER (PARTITION BY username ORDER BY date DESC) AS rn
  FROM t
) t2
WHERE rn = 1

Coût total: 61.5823

JOINTURE INTERNE

SELECT t.username, t.value
FROM t
INNER JOIN (
  SELECT username, MAX(date) AS date
  FROM t
  GROUP BY username
) tm ON t.username = tm.username AND t.date = tm.date;

Expliquez le coût total: 67.5439

JOINTURE EXTERNE GAUCHE

SELECT username, value
FROM t
LEFT OUTER JOIN t AS w ON t.username = w.username AND t.date < w.date
WHERE w.username IS NULL

Expliquez le coût total: 62.964


Les plans explicités proviennent d’une base de données contenant environ 10 000 lignes, stockée au format XML. Les requêtes utilisées contiennent également un prédicat "group_id = '1'".

2
Fabian Pijcke

Vous pouvez également utiliser la fonction de classement analytique

    with temp as 
(
select username, date, RANK() over (partition by username order by date desc) as rnk from t
)
select username, rnk from t where rnk = 1
1
imba22

Select * from table1 where lastest_date=(select Max(latest_date) from table1 where user=yourUserName)

Inner Query renverra la date la plus récente pour l'utilisateur actuel, Outer query extraira toutes les données en fonction du résultat de la requête interne.

0
Dheeraj Kumar

Pour Oracle, le résultat est trié par ordre décroissant et prend le premier enregistrement. Vous obtiendrez ainsi le dernier enregistrement:

select * from mytable
where rownum = 1
order by date desc
0
user2014518

J'ai utilisé cette façon de prendre le dernier enregistrement pour chaque utilisateur que j'ai sur ma table. C'était une requête pour obtenir le dernier emplacement du vendeur selon l'heure récemment détectée sur PDA périphériques.

CREATE FUNCTION dbo.UsersLocation()
RETURNS TABLE
AS
RETURN
Select GS.UserID, MAX(GS.UTCDateTime) 'LastDate'
From USERGPS GS
where year(GS.UTCDateTime) = YEAR(GETDATE()) 
Group By GS.UserID
GO
select  gs.UserID, sl.LastDate, gs.Latitude , gs.Longitude
        from USERGPS gs
        inner join USER s on gs.SalesManNo = s.SalesmanNo 
        inner join dbo.UsersLocation() sl on gs.UserID= sl.UserID and gs.UTCDateTime = sl.LastDate 
        order by LastDate desc
0
Mahmoud Hawa
SELECT t1.username, t1.date, value
FROM MyTable as t1
INNER JOIN (SELECT username, MAX(date)
            FROM MyTable
            GROUP BY username) as t2 ON  t2.username = t1.username AND t2.date = t1.date
0
David
SELECT *
FROM ReportStatus c
inner join ( SELECT 
  MAX(Date) AS MaxDate
  FROM ReportStatus ) m
on  c.date = m.maxdate
0
Narmadha
SELECT * FROM TABEL1 WHERE DATE= (SELECT MAX(CREATED_DATE) FROM TABEL1)
0
AJAY
SELECT Username, date, value
 from MyTable mt
 inner join (select username, max(date) date
              from MyTable
              group by username) sub
  on sub.username = mt.username
   and sub.date = mt.date

Adresserait le problème mis à jour. Cela pourrait ne pas fonctionner aussi bien sur les grandes tables, même avec une bonne indexation.

0
Philip Kelley

Ceci est similaire à l'une des réponses ci-dessus, mais à mon avis, il est beaucoup plus simple et ordonné. En outre, montre une bonne utilisation de l'instruction cross apply. Pour SQL Server 2005 et supérieur ...

select
    a.username,
    a.date,
    a.value,
from yourtable a
cross apply (select max(date) 'maxdate' from yourtable a1 where a.username=a1.username) b
where a.date=b.maxdate
0
James Moore

Ma petite compilation

  • self join meilleur que imbriqué select
  • mais group by ne vous donne pas primary key qui est préférable pour join
  • cette clé peut être donnée par partition by conjointement avec first_value ( docs )

Donc, voici une requête:

 sélectionnez 
 t. * 
 dans 
 table t jointure interne (
 sélectionnez une première valeur distincte (ID) sur (partition par ordre GroupColumn par DateColumn desc ) comme ID 
 du tableau 
 où FilterColumn = 'valeur' ​​
) j sur t.ID = j.ID 

Avantages:

  • Filtrer les données avec l'instruction where en utilisant n'importe quelle colonne
  • select toutes les colonnes des lignes filtrées

Les inconvénients:

  • Besoin de MS SQL Server à partir de 2012.
0
resnyanskiy

J'ai fait un peu pour mon application car il:

Ci-dessous la requête:

select distinct i.userId,i.statusCheck, l.userName from internetstatus 
as i inner join login as l on i.userID=l.userID 
where nowtime in((select max(nowtime) from InternetStatus group by userID));    
0
Sajee