각 사용자의 최신 레코드 날짜에 대해 SQL을 쿼리하는 방법


228

사용자가 로그온 할 때 수집 항목 인 테이블이 있습니다.

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

각 사용자에게 최신 날짜를 제공하는 쿼리를 작성하는 방법

업데이트 : 최신 날짜와 함께 가치를 가져야한다는 것을 잊었습니다.


7
어떤 데이터베이스를 사용하고 있습니까? MySQL, SQL- 서버, 오라클, ...?
Peter Lang

1
최신 날짜와 함께 제공되는 값 또는 최대 값과 최대 날짜가 필요합니까?
Matthew Jones

답변:


381
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

3
postgresql로 작업 할 때이 버전이 내부 조인 대신 IN (하위 쿼리)을 사용하는 것보다 빠릅니까?
TheOne

3
@TheOne 내 경험으로는 내부 조인을 사용하는 것이 상태보다 빠릅니다.
dada

14
이 접근 방식에주의하십시오. 사용자가 날짜 당 둘 이상의 레코드를 가지고있는 경우 사용자 당 둘 이상의 행을 리턴 할 수 있습니다 ( max(date)여러 레코드를 결합하는 날짜를 리턴 함). 이 문제를 피하려면 @dotjoe의 솔루션을 사용하는 것이 좋습니다 : stackoverflow.com/a/2411763/4406793 .
Marco Roy

@ RedFilter 이것은 내 문제에 완벽하게 작동했습니다. 그러한 기술적 인 질문에 감사드립니다. 그런데 특정 날짜에 대해 여러 개의 결과를 얻지 않기 위해 날짜 대신 날짜 시간을 사용했습니다
Muhammad Khan

왜 'and t.date = tm.MaxDate'그룹화가 충분하지 않습니까?
duldi

125

창 기능 사용 (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

1
어떤 Sybase 제품 / 버전을 설명 할 가치가 있습니다. Sybase ASE 16에서는 작동하지 않습니다.
levant 님이

2
이 방법의 가장 큰 장점은 파티션 당 하나의 행만 반환 username하고 (이 경우) max(date)다른 "응답 가능"필드와 같은 고유 한 "주문 가능"필드가 필요하지 않다는 것 입니다.
Marco Roy

1
@MarcoRoy가 말한 것에 무언가 추가하기 만하면 최대 날짜가 같은 레코드가 두 개 이상 있으면 쿼리를 변경하는 경우와 같이 쿼리를 변경하면 다른 레코드에 행 번호가 1이 될 수 있습니다. 결과가 일치하지 않을 수 있습니다. 그러나 당신이 정말로 신경 쓰지 않는 한, 이것은 문제가되지 않아야합니다. 날짜 이후에 PK를 추가하면이 문제를 해결할 수 있습니다. 예를 들면 다음과 같습니다 order by date desc, id desc)..
Andrew

40

대부분의 개발자는 대량의 데이터에 미치는 영향을 고려하지 않고 인라인 쿼리를 사용합니다.

간단히 말해서 다음을 수행하면됩니다.

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;

3
실제로 이것은 중복에 대해서만 작동합니다. 값이 2 이상인 경우 a.date <b.date 조건이 작동하지 않습니다. 즉, 왼쪽 외부 조인 작업에 대한 아이디어가 중요하지만 일반적인 해결책은 아닙니다. 이 답변에있는 것.
iversoncru

흥미롭게도 Sybase ASE 16은 작은 (<10k 행) 테이블에서는 잘 작동하지만 더 큰 테이블 (> 100k 행)에서는 중단됩니다. 관계형 DB가 탁월해야하는 완벽한 예라고 생각했습니다.
levant pied

1
@levantpied ... 예. 왼쪽 조인은 더 큰 데이터 세트에서 비용이 많이 듭니다. 필터 조건을 결합 자체에 설정하여 가능한 경우 어떤 방식 으로든 처리 할 수 ​​있도록하여 성능을 조정할 수 있습니다.
sujeet

21

사용자의 최대 날짜가 포함 된 전체 행을 가져 오려면 다음을 수행하십시오.

select username, date, value
from tablename where (username, date) in (
    select username, max(date) as date
    from tablename
    group by username
)

1
MySQL을위한 작업
School Boy

1
특정 사용자에 대해 동일한 날짜를 가진 레코드가 두 개 이상인 경우 복제본을 제공합니다. 이것을 원하거나 원치 않을 수 있습니다.
Andrew

이 SQL은 in 절과 함께 Oracle에서 느리며 인덱스를 사용하지 않습니다.
meadlai

9
SELECT *     
FROM MyTable T1    
WHERE date = (
   SELECT max(date)
   FROM MyTable T2
   WHERE T1.username=T2.username
)

4
이것은 또 다른 가능한 해결책이지만 일반적으로 이것을 해결하는 좋은 방법은 아닙니다. 이렇게하면 테이블의 각 이름에 대해 내부 쿼리가 한 번 실행되어 크기가 큰 테이블의 경우 속도가 크게 느려집니다. where 절의 첫 번째 쿼리에서 요소가없는 별도의 쿼리를 수행하면 두 테이블을 결합하는 것이 일반적 으로 더 빠릅니다.
Scott Chamberlain

이것은 구현에 고유하지 않은 더 이해하기 쉬운 솔루션 중 하나라는 훌륭한 기능을 가지고 있습니다.
Michael Szczepaniak

7

내 경험상 가장 빠른 방법은 테이블에 새로운 행이없는 각 행을 취하는 것입니다.

또 다른 장점은 사용 된 구문이 매우 단순하고 쿼리의 의미를 파악하기가 쉽다는 것입니다 (사용자 이름에 대해 새로운 행이 존재하지 않도록 모든 행을 취하십시오).

존재하지 않음

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

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

내부 가입

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;

왼쪽 외부 조인

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

NOT EXISTS 버전을 이해하는 데 어려움이 있습니다. 하위 쿼리 부분에서 집계가 누락되지 않았습니까? 내 테이블 에서이 작업을 실행하면 테이블에있는 40 명의 직원으로부터 3 명의 직원 레코드 만 가져옵니다. 40 개 이상의 레코드를 가져와야합니다. 내부 쿼리에서 사용자 이름과도 일치하지 않아야합니까?
내쉬

그것은 다음을 사용하여 나를 위해 작동합니다 :SELECT username, value FROM t WHERE NOT EXISTS ( SELECT * FROM t AS witness WHERE witness.date > t.date AND witness.username = t.username );
Narshe

NOT EXISTS를 살펴본 결과 "각 사용자의 최신 날짜를 알려주는 쿼리"와는 대조적으로 모든 사용자에 대해 더 높은 항목 만 반환하려고합니다.
Tasos Zervos

당신은 옳습니다, 나는 나의 쿼리를 업데이트합니다. 귀하의 의견에 감사드립니다! @Narshe 죄송하지만 어떤 이유로 든 귀하의 의견을 놓쳤습니다 : / 그러나 당신은 절대적으로 옳습니다.
Fabian Pijcke

2

이 질문은 편집 한 질문에 대한 올바른 결과를 제공합니다.

하위 쿼리는 최신 날짜의 행만 찾도록하고 외부 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

분석 순위 함수를 사용할 수도 있습니다

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

업데이트 된 문제를 해결합니다. 인덱싱이 좋은 경우에도 큰 테이블에서는 제대로 작동하지 않을 수 있습니다.


0
SELECT *
FROM ReportStatus c
inner join ( SELECT 
  MAX(Date) AS MaxDate
  FROM ReportStatus ) m
on  c.date = m.maxdate

0

Oracle의 경우 결과 세트를 내림차순으로 정렬하고 첫 번째 레코드를 가져 오므로 최신 레코드를 얻습니다.

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

0
SELECT DISTINCT Username, Dates,value 
FROM TableName
WHERE  Dates IN (SELECT  MAX(Dates) FROM TableName GROUP BY Username)


Username    Dates       value
bob         2010-02-02  1.2       
brad        2010-01-02  1.1       
fred        2010-01-03  1.0       

여러 사용자가 같은 날짜에 주문한 경우 작동하지 않을 수 있습니다. 1 월 2 일에 브래드와 밥이 둘을 주문했다면?
AHiggins

사용자 이름별로 그룹화하여 작동하며 결과는 다음과 같습니다. 사용자 이름 날짜 bob 2010-02-02 1.2 brad 2010-02-02 1.4 fred 2010-01-03 1.0
wara

0
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

4
구현이나 설명에 관한 한두 문장은 양질의 답변을 만들기 위해 먼 길을 간다.

0

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

내부 쿼리는 현재 사용자의 최신 날짜를 반환하고 외부 쿼리는 내부 쿼리 결과에 따라 모든 데이터를 가져옵니다.


0

이 방법을 사용하여 테이블에있는 각 사용자의 마지막 레코드를 가져 왔습니다. 최근 PDA 장치에서 검색된 시간에 따라 영업 사원의 마지막 위치를 찾는 것이 쿼리였습니다.

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
SELECT * FROM TABEL1 WHERE DATE= (SELECT MAX(CREATED_DATE) FROM TABEL1)

StackOverflow에 오신 것을 환영합니다. 도와 주셔서 감사합니다. 귀하와 같은 코드 전용 답변은 솔루션을 설명하는 답변과 비교할 때 덜 감사합니다.
Yunnosch

양질의 답변을 제공 하는 방법을 알아 보십시오 .
thewaywe는

과. 각 사용자 이름에 대해 MAX로 돌아 가지 않고 최신 단일 행으로 돌아갑니다.
IrvineCAGuy

0

내 작은 컴파일

  • join중첩보다 자기 낫다select
  • 그러나 group by당신에게 primary key바람직한 것을 주지 않습니다join
  • 이 키는 ( docs ) partition by와 함께 제공 될 수 있습니다.first_value

그래서 여기 쿼리가 있습니다 :

고르다
 티.*
...에서 
 테이블 t 내부 조인 (
  ID로 고유 한 first_value (ID)를 선택합니다 (DateColumn desc를 기준으로 GroupColumn 순서로 파티션).
  테이블에서
  여기서 FilterColumn = 'value'
 ) t.ID의 j = j.ID

장점 :

  • where열을 사용하여 명령문으로 데이터 필터링
  • select 필터링 된 행의 모든 ​​열

단점 :

  • 2012 년부터 MS SQL Server가 필요합니다.

0

나는 내 응용 프로그램을 위해 다소 노력했다.

아래는 쿼리입니다.

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

이것은 위의 답변 중 하나와 비슷하지만 내 의견으로는 훨씬 간단하고 깔끔합니다. 또한 cross apply 문에 대한 유용한 사용법을 보여줍니다. SQL Server 2005 이상 ...

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
SELECT MAX(DATE) AS dates 
FROM assignment  
JOIN paper_submission_detail ON  assignment.PAPER_SUB_ID = 
     paper_submission_detail.PAPER_SUB_ID 

1
이 코드가 문제를 해결하는 방법과 이유에 대한 설명포함 하여 질문을 해결할 수는 있지만 게시물의 품질을 향상시키는 데 도움이되고 더 많은 투표를 할 수 있습니다. 지금 질문하는 사람이 아니라 독자들에게 질문에 대답하고 있음을 기억하십시오. 제발 편집 설명을 추가하고 제한 및 가정이 적용 무엇의 표시를 제공하는 답변을. 검토에서
이중 경고음

-2

이것은 또한 사용자를위한 모든 최신 항목을 얻기 위해 작동해야합니다.

SELECT username, MAX(date) as Date, value
FROM MyTable
GROUP BY username, value

1
안녕하세요, 값 열은 group by 절에 있어야합니다.
Juan Ruiz de Castilla

-4

집계 함수 MAX 및 GROUP BY를 사용합니다.

SELECT username, MAX(date), value FROM tablename GROUP BY username, value

7
수정 사항은 행 value과 연결된 항목이 아닌 임의의 항목 만 선택합니다 MAX(date).
Alison R.

최대 날짜를 제공하지만 사용자 이름과 값은 동일한 레코드가 아닐 수 있습니다.
SKR
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.