как запросить sql для последней даты записи для каждого пользователя - PullRequest
174 голосов
/ 09 марта 2010

У меня есть таблица, которая представляет собой набор записей о том, когда пользователь вошел в систему.

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..

Как мне создать запрос, который даст мне самую последнюю дату для каждого пользователя?

Обновление: Я забыл, что мне нужно иметь значение, соответствующее самой последней дате.

Ответы [ 21 ]

298 голосов
/ 09 марта 2010
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
80 голосов
/ 09 марта 2010

Использование оконных функций (работает в 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
34 голосов
/ 18 августа 2016

Я вижу, что большинство разработчиков используют встроенный запрос без учета его влияния на огромные данные.

Просто вы можете достичь этого:

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;
19 голосов
/ 09 марта 2010

Чтобы получить всю строку, содержащую максимальную дату для пользователя:

select username, date, value
from tablename where (username, date) in (
    select username, max(date) as date
    from tablename
    group by username
)
7 голосов
/ 03 июня 2013
SELECT *     
FROM MyTable T1    
WHERE date = (
   SELECT max(date)
   FROM MyTable T2
   WHERE T1.username=T2.username
)
2 голосов
/ 09 марта 2010

Это должно дать вам правильный результат для вашего отредактированного вопроса.

Подзапрос гарантирует, что найдутся только строки с самой последней датой, а внешний GROUP BY позаботится о связях. Если для одного и того же пользователя есть две записи на одну и ту же дату, она вернет запись с самым высоким значением 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
1 голос
/ 22 августа 2018

Из моего опыта самый быстрый способ - это взять каждую строку, для которой в таблице нет новой строки. Вот небольшой тест с некоторыми данными, которые у меня под рукой.

Еще одним преимуществом является то, что используемый синтаксис очень прост и что значение запроса довольно легко понять (возьмите все строки так, чтобы для рассматриваемого имени пользователя не было новой строки).

НЕ СУЩЕСТВУЕТ

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

Объясните общую стоимость: 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

Общая стоимость: 61,5823

ВНУТРЕННИЙ РЕЙТИНГ

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;

Объясните общую стоимость: 67,5439

ВЛЕВО НАРУЖНОЕ СОЕДИНЕНИЕ

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

Объясните общую стоимость: 62,964


Планы объяснения поступают из базы данных с примерно 10 тыс. Строк, которые хранятся в формате XML. Используемые запросы также содержат предикат "group_id = '1'".

1 голос
/ 26 сентября 2018

Вы также можете использовать аналитическую функцию ранга

    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
0 голосов
/ 27 февраля 2017

Я использовал этот способ, чтобы взять последнюю запись для каждого пользователя, который у меня есть на столе. Это был запрос для определения последнего местоположения продавца в соответствии с недавним временем, обнаруженным на устройствах КПК.

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 голосов
/ 04 января 2017

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

Внутренний запрос вернет самую последнюю дату для текущего пользователя, Внешний запрос извлечет все данные в соответствии с внутренним результатом запроса.

...