표:
UserId, Value, Date.
UserId, 각 UserId의 max (Date)에 대한 값을 가져오고 싶습니다. 즉, 최신 날짜를 가진 각 UserId의 값입니다. SQL로 간단하게 수행 할 수있는 방법이 있습니까? (바람직하게 오라클)
업데이트 : 모든 모호성에 대한 사과 : 모든 UserId를 가져와야합니다. 그러나 각 UserId에 대해 해당 사용자가 최신 날짜를 가진 행만 해당합니다.
답변
그러면 my_date 열 값이 해당 사용자 ID의 최대 my_date 값과 동일한 모든 행을 검색합니다. 최대 날짜가 여러 행에있는 사용자 ID에 대해 여러 행을 검색 할 수 있습니다.
select userid,
my_date,
...
from
(
select userid,
my_date,
...
max(my_date) over (partition by userid) max_my_date
from users
)
where my_date = max_my_date
“분석 기능 락”
편집 : 첫 번째 의견과 관련하여 …
“분석 쿼리 및 자체 조인을 사용하면 분석 쿼리의 목적이 무효화됩니다.”
이 코드에는 자체 조인이 없습니다. 대신 인라인 뷰 결과에 분석 함수가 포함 된 술어가 있습니다 (매우 다른 문제이며 완전히 표준 관행 임).
“Oracle의 기본 창은 파티션의 첫 번째 행에서 현재 행까지입니다.”
windowing 절은 order by 절이있는 경우에만 적용 할 수 있습니다. order by 절이 없으면 기본적으로 windowing 절이 적용되지 않으며 명시 적으로 지정할 수 없습니다.
코드가 작동합니다.
답변
많은 사람들이 하위 쿼리 또는 다른 공급 업체별 기능을 사용하여이 작업을 수행하는 것을 보았지만 종종 다음과 같은 방식으로 하위 쿼리없이 이러한 종류의 쿼리를 수행합니다. 일반 표준 SQL을 사용하므로 모든 RDBMS 브랜드에서 작동해야합니다.
SELECT t1.*
FROM mytable t1
LEFT OUTER JOIN mytable t2
ON (t1.UserId = t2.UserId AND t1."Date" < t2."Date")
WHERE t2.UserId IS NULL;
즉 t1
, 동일 UserId
하고 더 큰 날짜를 가진 다른 행이없는 곳 에서 행을 가져옵니다 .
(식별자 “Date”는 SQL 예약어이므로 구분 기호에 넣습니다.)
의 경우 t1."Date" = t2."Date"
두배가 나타납니다. 일반적으로 테이블에는 auto_inc(seq)
키가 있습니다 (예 🙂 id
. 이중화를 피하기 위해 다음을 사용할 수 있습니다.
SELECT t1.*
FROM mytable t1
LEFT OUTER JOIN mytable t2
ON t1.UserId = t2.UserId AND ((t1."Date" < t2."Date")
OR (t1."Date" = t2."Date" AND t1.id < t2.id))
WHERE t2.UserId IS NULL;
@ Farhan의 의견 :
자세한 설명은 다음과 같습니다.
외부 조인이 t1
와 조인을 시도합니다 t2
. 기본적으로 모든 결과 t1
가 반환되고 에 일치하는 항목이 있으면t2
반환됩니다. t2
의 지정된 행에 일치하는 항목이 없으면 t1
쿼리는 여전히의 행을 반환하고 모든 열의 자리 표시 자로 t1
사용합니다 . 이것이 외부 조인이 일반적으로 작동하는 방식입니다.NULL
t2
이 쿼리의 트릭 t2
은 동일 userid
하고 더 큰 일치해야하는 조인의 일치 조건을 디자인하는 것 date
입니다. 행이 존재하면되는 아이디어 t2
가 더 큰이 date
, 다음의 행 t1
이 비교있어 수없는 큰 일 date
이에 대한을 userid
. 그러나 일치하는 것이 없으면 (즉 , 행 t2
보다 큰 행이없는 경우) 행이 주어진 행에 대해 가장 큰 행 임을 알 수 있습니다.date
t1
t1
date
userid
이러한 경우의 열 (때 일치가 없다) t2
됩니다 NULL
에 지정된에도 열 조인 조건 -. 그래서 우리가 사용하는 이유는 주어진 WHERE t2.UserId IS NULL
행보다 큰 행을 찾을 수없는 경우를 찾고 있기 때문 입니다.date
userid
답변
SELECT userid, MAX(value) KEEP (DENSE_RANK FIRST ORDER BY date DESC)
FROM table
GROUP BY userid
답변
정확한 열 이름을 모르지만 다음과 같습니다.
사용자 ID, 값을 선택하십시오 사용자 u1에서 여기서 날짜 = (최대 선택 (날짜) 사용자 u2에서 여기서 u1.userid = u2.userid)
답변
일하고 있지는 않지만 Oracle이 제공 해야하는 것은 아니지만 Oracle은 IN 절에서 여러 열을 일치시킬 수 있다는 것을 기억합니다. 생각.
아마도 이런 식일 것입니다 (열 목록을 괄호로 묶어야하는지 여부를 기억할 수 없습니다).
SELECT *
FROM MyTable
WHERE (User, Date) IN
( SELECT User, MAX(Date) FROM MyTable GROUP BY User)
편집 : 그냥 진짜 시도했습니다.
SQL> create table MyTable (usr char(1), dt date);
SQL> insert into mytable values ('A','01-JAN-2009');
SQL> insert into mytable values ('B','01-JAN-2009');
SQL> insert into mytable values ('A', '31-DEC-2008');
SQL> insert into mytable values ('B', '31-DEC-2008');
SQL> select usr, dt from mytable
2 where (usr, dt) in
3 ( select usr, max(dt) from mytable group by usr)
4 /
U DT
- ---------
A 01-JAN-09
B 01-JAN-09
다른 곳에서 언급 된 신기한 물건 중 일부가 더 성능이 좋을 수도 있지만 작동합니다.
답변
Oracle을 요청했지만 SQL 2005에서는 다음을 사용합니다.
-- Single Value
;WITH ByDate
AS (
SELECT UserId, Value, ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY Date DESC) RowNum
FROM UserDates
)
SELECT UserId, Value
FROM ByDate
WHERE RowNum = 1
-- Multiple values where dates match
;WITH ByDate
AS (
SELECT UserId, Value, RANK() OVER (PARTITION BY UserId ORDER BY Date DESC) Rnk
FROM UserDates
)
SELECT UserId, Value
FROM ByDate
WHERE Rnk = 1
답변
나는 그것을 테스트 할 오라클이 없지만 가장 효율적인 솔루션은 분석 쿼리를 사용하는 것입니다. 다음과 같이 보일 것입니다 :
SELECT DISTINCT
UserId
, MaxValue
FROM (
SELECT UserId
, FIRST (Value) Over (
PARTITION BY UserId
ORDER BY Date DESC
) MaxValue
FROM SomeTable
)
외부 쿼리를 제거하고 내부를 구별 할 수 있다고 생각하지만 확실하지 않습니다. 그 동안 나는 이것이 작동한다는 것을 안다.
분석 쿼리에 대해 배우려면 http://www.orafaq.com/node/55 및 http://www.akadia.com/services/ora_analytic_functions.html을 읽으십시오 . 다음은 간단한 요약입니다.
후드 분석 쿼리에서 전체 데이터 세트를 정렬 한 다음 순차적으로 처리하십시오. 처리 할 때 특정 기준에 따라 데이터 세트를 분할 한 다음 각 행에 대해 일부 창을보고 (기본값은 현재 행에 대한 파티션의 첫 번째 값-기본값은 가장 효율적 임) a를 사용하여 값을 계산할 수 있습니다 분석 함수 수 (목록은 집계 함수와 매우 유사 함)
이 경우 내부 쿼리의 기능은 다음과 같습니다. 전체 데이터 세트는 UserId, Date DESC로 정렬됩니다. 그런 다음 한 번에 처리합니다. 각 행에 대해 UserId 및 해당 UserId에 대해 표시된 첫 번째 날짜를 반환합니다 (날짜가 DESC로 정렬되므로 최대 날짜 임). 이렇게하면 중복 된 행으로 답을 얻을 수 있습니다. 그런 다음 외부 DISTINCT가 중복을 찌그러 뜨립니다.
이것은 특히 분석 쿼리의 화려한 예가 아닙니다. 훨씬 더 큰 승리를 거두려면 재정 영수증 표를 작성하고 각 사용자 및 영수증에 대해 계산 한 총액을 지불하십시오. 분석 쿼리는이를 효율적으로 해결합니다. 다른 솔루션은 효율성이 떨어집니다. 이것이 그들이 2003 SQL 표준의 일부인 이유입니다. (불행히도 Postgres에는 아직 없습니다. Grrr …)