programing

다른 열의 각 고유 값에 대해 열에 대한 최대 값이 있는 행을 가져옵니다.

javajsp 2023. 2. 23. 22:03

다른 열의 각 고유 값에 대해 열에 대한 최대 값이 있는 행을 가져옵니다.

표:

UserId, Value, Date.

각 UserId의 UserId, max(날짜) 값을 가져오고 싶습니다.즉, 최신 날짜를 가진 각 UserId의 값입니다.이를 SQL로 간단하게 수행할 수 있는 방법이 있습니까? (가능하다면 Oracle)

업데이트: 불명확한 점이 있으면 죄송합니다.모든 사용자 ID를 가져와야 합니다.단, 각 UserId에 대해 해당 사용자의 최신 날짜가 있는 행만 해당됩니다.

많은 사람들이 서브쿼리나 윈도우 기능을 사용하는 것을 볼 수 있지만, 저는 서브쿼리 없이 다음과 같은 방법으로 쿼리를 하는 경우가 많습니다.일반 표준 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;

행은 행, 옵행 from from from from from from from from from from in 、 、 을 、 the 、 the the 。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에서 다시 코멘트:

자세한 설명은 다음과 같습니다.

이 결합을 합니다.t1t2로는 " " " 의 모든 는 " " " 입니다.t1에 일치할 경우 반환됩니다.t2, 그것도 반환됩니다. 하는 것이 없는 t2t1 "이행" 행을 t1및를 사용합니다.NULLt2 조인(outer 합니다.그것이 일반적인 외부 결합의 작동 방식입니다.

을 '조인'으로 입니다.t2일치해야 합니다. userid, 그 이상 date 행이 t2 큰 을 가지고 있다date에 의 이 나옵니다.t1 비교해도 최고는 될 수 없다date 때문에userid하는 것이 경우,즉이 없는 , 행이 없는 t2 큰 더 a로datet1의.-- 의 -- 。t1 큰 이었습니다.date의 기간 userid.

하지 않을 )의 됩니다.t2 되다NULL-- 가입 조건에도 지정된 열이 있습니다. 건 으 조 정 찬 럼 가 니 even condition마다 in the the join specified-- join입컬지지도된로 columns condition even.. So that's why we use 그래서 우리가 사용하는 것은WHERE t2.UserId IS NULL, 우가 더 큰 was 큰 이 견 은 고 문 기 때다 because we'니있입찾 where for경 found row with a않 the발행 greater를 no지re searchingdate for the given 기정사실상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 절이 적용되지 않으며 명시적으로 지정할 수 없습니다.

코드는 동작한다.

SELECT userid, MAX(value) KEEP (DENSE_RANK FIRST ORDER BY date DESC)
  FROM table
  GROUP BY userid

정확한 열 이름은 모르지만 다음과 같습니다.

SELECT userid, value
FROM users u1
WHERE date = (
    SELECT MAX(date)
    FROM users u2
    WHERE 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

테스트할 Oracle은 없지만 가장 효율적인 솔루션은 분석 쿼리를 사용하는 것입니다.다음과 같이 표시됩니다.

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 여기 간단한 요약이 있습니다.

후드 분석 쿼리에서 전체 데이터 세트를 정렬한 다음 순차적으로 처리합니다.데이터 세트를 처리할 때 특정 기준에 따라 데이터 세트를 분할한 다음 각 행에 대해 일부 창(기본값에서 현재 행으로 분할된 첫 번째 값)을 보고 여러 분석 함수(집약 함수 목록과 매우 유사함)를 사용하여 값을 계산할 수 있습니다.

이 경우 내부 쿼리는 다음과 같이 동작합니다.전체 데이터 집합은 UserId를 기준으로 정렬되고 Date DESC를 기준으로 정렬됩니다.그런 다음 한 번에 처리됩니다.각 행에 대해 UserId와 해당 UserId에 대해 처음 표시된 날짜를 반환합니다(날짜는 DESC로 정렬되므로 최대 날짜입니다).중복된 행에 대한 답변을 제공합니다.그런 다음 외부 DISTINCT가 중복 항목을 스퀴시합니다.

이것은 분석 질의의 특별한 예는 아닙니다.더 큰 성공을 거두려면 재무 영수증 표를 가져와 각 사용자와 영수증에 대해 지불한 총 금액을 계산하는 것을 고려하십시오.분석 쿼리를 통해 효율적으로 해결할 수 있습니다.다른 솔루션은 효율성이 떨어집니다.그래서 2003년 SQL 규격에 포함되어 있습니다.(안타깝게도 Postgres는 아직 없습니다.으르렁...)

Qualificate 조항이 가장 간단하고 최선이지 않을까요?

select userid, my_date, ...
from users
qualify rank() over (partition by userid order by my_date desc) = 1

참고로, 여기 Teradata에서는 이 Qualificate 버전에서는 17대에서, '인라인 뷰'/Aldridge 솔루션 #1에서는 23대에서 적절한 크기 테스트를 실시합니다.

그럼 분석 함수와 함께 Top n 쿼리를 사용할 수 있습니다.rank서브쿼리 없이 이를 매우 간결하게 달성하려면:

select *
from your_table
order by rank() over (partition by user_id order by my_date desc)
fetch first 1 row with ties;

위에서는 사용자별로 my_date가 최대인 행이 모두 반환됩니다.

최대 날짜를 가진 행을 하나만 사용하는 경우rank와 함께row_number:

select *
from your_table
order by row_number() over (partition by user_id order by my_date desc)
fetch first 1 row with ties; 

Postgre 포함SQL 8.4 이후에는 다음을 사용할 수 있습니다.

select user_id, user_value_1, user_value_2
  from (select user_id, user_value_1, user_value_2, row_number()
          over (partition by user_id order by user_date desc) 
        from users) as r
  where r.row_number=1

직장에서 "실시간" 예를 작성하기만 하면 됩니다. :)

이것은 같은 날짜에 UserId에 대해 여러 값을 지원합니다.

열:사용자 ID, 값, 날짜

SELECT
   DISTINCT UserId,
   MAX(Date) OVER (PARTITION BY UserId ORDER BY Date DESC),
   MAX(Values) OVER (PARTITION BY UserId ORDER BY Date DESC)
FROM
(
   SELECT UserId, Date, SUM(Value) As Values
   FROM <<table_name>>
   GROUP BY UserId, Date
)

MAX 대신 FIRST_VALUE를 사용하여 설명 계획에서 조회할 수 있습니다.그걸 가지고 놀 시간이 없었어요.

물론 큰 테이블을 검색할 경우 쿼리에 풀 힌트를 사용하는 것이 좋습니다.

파티에는 늦었지만 다음 해킹은 관련된 서브쿼리와 분석 기능을 모두 능가하지만 한 가지 제약이 있습니다. 값은 문자열로 변환되어야 합니다.날짜, 숫자, 기타 문자열에 사용할 수 있습니다.코드는 좋아 보이지 않지만 실행 프로파일은 양호합니다.

select
    userid,
    to_number(substr(max(to_char(date,'yyyymmdd') || to_char(value)), 9)) as value,
    max(date) as date
from 
    users
group by
    userid

이 코드가 잘 작동하는 이유는 테이블을 한 번만 스캔하면 되기 때문입니다.인덱스가 필요하지 않으며, 가장 중요한 것은 대부분의 분석 기능이 그러하듯이 테이블을 정렬할 필요가 없습니다.단일 사용자 ID에 대한 결과를 필터링해야 하는 경우 인덱스가 도움이 됩니다.

내림차순에서 고유한 순위를 지정하는 데 사용합니다.Date for each 각각에 대해서UserId, , then filter to the first row for each 그 후, 각 행의 첫 번째 행으로 필터링 합니다.UserId-어, 엑스테네요. -네.ROW_NUMBER1)= 1)

SELECT UserId, Value, Date
FROM (SELECT UserId, Value, Date,
        ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY Date DESC) rn
      FROM users) u
WHERE rn = 1;

사용하는 Postgres를 사용할 수 .array_agg

SELECT userid,MAX(adate),(array_agg(value ORDER BY adate DESC))[1] as value
FROM YOURTABLE
GROUP BY userid

Oracle에 대해서는 잘 모릅니다.이게 내가 생각해낸 거야

SELECT 
  userid,
  MAX(adate),
  SUBSTR(
    (LISTAGG(value, ',') WITHIN GROUP (ORDER BY adate DESC)),
    0,
    INSTR((LISTAGG(value, ',') WITHIN GROUP (ORDER BY adate DESC)), ',')-1
  ) as value 
FROM YOURTABLE
GROUP BY userid 

두 쿼리 모두 승인된 답변과 동일한 결과를 반환합니다.SQLFiddles 참조:

  1. 인정된 답변
  2. Postgres를 사용한 솔루션
  3. 오라클을 사용한 솔루션

이런 것 같아요.(구문의 오류는 용서해주세요.이 시점에서는 HQL을 사용하는 것이 익숙합니다!)

편집: 질문도 잘못 읽습니다!쿼리를 수정했습니다...

SELECT UserId, Value
FROM Users AS user
WHERE Date = (
    SELECT MAX(Date)
    FROM Users AS maxtest
    WHERE maxtest.UserId = user.UserId
)

이전 질문에서 이 변형을 만드신 것 같습니다.

SELECT UserId, Value FROM Users U1 WHERE 
Date = ( SELECT MAX(Date)    FROM Users where UserId = U1.UserId)
Select  
   UserID,  
   Value,  
   Date  
From  
   Table,  
   (  
      Select  
          UserID,  
          Max(Date) as MDate  
      From  
          Table  
      Group by  
          UserID  
    ) as subQuery  
Where  
   Table.UserID = subQuery.UserID and  
   Table.Date = subQuery.mDate  
select VALUE from TABLE1 where TIME = 
   (select max(TIME) from TABLE1 where DATE= 
   (select max(DATE) from TABLE1 where CRITERIA=CRITERIA))

(T-SQL) 먼저 모든 사용자와 해당 최대 날짜를 가져옵니다.표를 참조하여 maxdates에 있는 사용자의 해당 값을 찾습니다.

create table users (userid int , value int , date datetime)
insert into users values (1, 1, '20010101')
insert into users values (1, 2, '20020101')
insert into users values (2, 1, '20010101')
insert into users values (2, 3, '20030101')

select T1.userid, T1.value, T1.date 
    from users T1,
    (select max(date) as maxdate, userid from users group by userid) T2    
    where T1.userid= T2.userid and T1.date = T2.maxdate

결과:

userid      value       date                                    
----------- ----------- -------------------------- 
2           3           2003-01-01 00:00:00.000
1           2           2002-01-01 00:00:00.000

정답은 Oracle뿐입니다.다음은 모든 SQL에 대한 좀 더 복잡한 답변입니다.

전체 숙제 결과(과제 점수 최대합계)가 가장 좋은 사람은 누구입니까?

SELECT FIRST, LAST, SUM(POINTS) AS TOTAL
FROM STUDENTS S, RESULTS R
WHERE S.SID = R.SID AND R.CAT = 'H'
GROUP BY S.SID, FIRST, LAST
HAVING SUM(POINTS) >= ALL (SELECT SUM (POINTS)
FROM RESULTS
WHERE CAT = 'H'
GROUP BY SID)

그리고 더 어려운 예로는 설명이 필요하지만 시간 atm은 없습니다.

2008년에 가장 인기 있는 책(ISBN 및 제목)을 제시합니다.즉, 즉 2008년에 가장 많이 빌린 책입니다.

SELECT X.ISBN, X.title, X.loans
FROM (SELECT Book.ISBN, Book.title, count(Loan.dateTimeOut) AS loans
FROM CatalogEntry Book
LEFT JOIN BookOnShelf Copy
ON Book.bookId = Copy.bookId
LEFT JOIN (SELECT * FROM Loan WHERE YEAR(Loan.dateTimeOut) = 2008) Loan 
ON Copy.copyId = Loan.copyId
GROUP BY Book.title) X
HAVING loans >= ALL (SELECT count(Loan.dateTimeOut) AS loans
FROM CatalogEntry Book
LEFT JOIN BookOnShelf Copy
ON Book.bookId = Copy.bookId
LEFT JOIN (SELECT * FROM Loan WHERE YEAR(Loan.dateTimeOut) = 2008) Loan 
ON Copy.copyId = Loan.copyId
GROUP BY Book.title);

이게 도움이 됐으면 좋겠는데..:)

안부 전해 주세요, 거스

특정 사용자 ID에 대해 날짜가 고유하다고 가정하면 TSQL은 다음과 같습니다.

SELECT 
    UserTest.UserID, UserTest.Value
FROM UserTest
INNER JOIN
(
    SELECT UserID, MAX(Date) MaxDate
    FROM UserTest
    GROUP BY UserID
) Dates
ON UserTest.UserID = Dates.UserID
AND UserTest.Date = Dates.MaxDate 

파티션 KEEP, DEXE_RANK 개념이 없는 MySQL용 솔루션.

select userid,
       my_date,
       ...
from
(
select @sno:= case when @pid<>userid then 0
                    else @sno+1
    end as serialnumber, 
    @pid:=userid,
       my_Date,
       ...
from   users order by userid, my_date
) a
where a.serialnumber=0

참고 자료: http://benincampus.blogspot.com/2013/08/select-rows-which-have-maxmin-value-in.html

select userid, value, date
  from thetable t1 ,
       ( select t2.userid, max(t2.date) date2 
           from thetable t2 
          group by t2.userid ) t3
 where t3.userid t1.userid and
       t3.date2 = t1.date

IMHO 이거 되는구나.HTH

이거면 될 것 같은데?

Select
T1.UserId,
(Select Top 1 T2.Value From Table T2 Where T2.UserId = T1.UserId Order By Date Desc) As 'Value'
From
Table T1
Group By
T1.UserId
Order By
T1.UserId

첫 번째 시도에서는 질문을 잘못 읽었습니다.상위 답변에 이어 올바른 결과를 얻을 수 있는 완전한 예를 다음에 제시하겠습니다.

CREATE TABLE table_name (id int, the_value varchar(2), the_date datetime);

INSERT INTO table_name (id,the_value,the_date) VALUES(1 ,'a','1/1/2000');
INSERT INTO table_name (id,the_value,the_date) VALUES(1 ,'b','2/2/2002');
INSERT INTO table_name (id,the_value,the_date) VALUES(2 ,'c','1/1/2000');
INSERT INTO table_name (id,the_value,the_date) VALUES(2 ,'d','3/3/2003');
INSERT INTO table_name (id,the_value,the_date) VALUES(2 ,'e','3/3/2003');

--

  select id, the_value
      from table_name u1
      where the_date = (select max(the_date)
                     from table_name u2
                     where u1.id = u2.id)

--

id          the_value
----------- ---------
2           d
2           e
1           b

(3 row(s) affected)

중복도 처리됩니다(각 user_id에 대해 1개의 행을 반환합니다).

SELECT *
FROM (
  SELECT u.*, FIRST_VALUE(u.rowid) OVER(PARTITION BY u.user_id ORDER BY u.date DESC) AS last_rowid
  FROM users u
) u2
WHERE u2.rowid = u2.last_rowid

방금 테스트한 결과 로그 테이블에서 작동하는 것 같습니다.

select ColumnNames, max(DateColumn) from log  group by ColumnNames order by 1 desc

이것은 다음과 같이 간단해야 합니다.

SELECT UserId, Value
FROM Users u
WHERE Date = (SELECT MAX(Date) FROM Users WHERE UserID = u.UserID)

(UserID, Date)가 고유할 경우, 즉 같은 사용자에 대해 날짜가 두 번 표시되지 않는 경우:

select TheTable.UserID, TheTable.Value
from TheTable inner join (select UserID, max([Date]) MaxDate
                          from TheTable
                          group by UserID) UserMaxDate
     on TheTable.UserID = UserMaxDate.UserID
        TheTable.[Date] = UserMaxDate.MaxDate;
select   UserId,max(Date) over (partition by UserId) value from users;

언급URL : https://stackoverflow.com/questions/121387/fetch-the-rows-which-have-the-max-value-for-a-column-for-each-distinct-value-of