SQL Server : MAX (DATE)가있는 행만 선택


109

데이터 테이블이 있습니다 (db는 MSSQL입니다).

    ID  OrderNO PartCode  Quantity DateEntered
    417 2144     44917    100      18-08-11
    418 7235     11762    5        18-08-11
    419 9999     60657    100      18-08-11
    420 9999     60657    90       19-08-11

OrderNO, PartCode 및 Quantity를 반환하는 쿼리를 만들고 싶지만 마지막으로 등록 된 주문에 대해서만.

예제 테이블에서 다음 정보를 얻고 싶습니다.

     OrderNO PartCode  Quantity     
     2144     44917    100      
     7235     11762    5        
     9999     60657    90      

주문 9999에 대해 하나의 라인 만 반품되었습니다.

감사!


2
귀하의 의견에서 ROW_NUMBER () 답변으로 이동하십시오. 더 길어 보일 수 있지만 내 경험상 적절한 색인을 사용하면 훨씬 빠릅니다.
MatBailie

감사합니다 Dems, 귀하의 노력에 감사드립니다.
GEMI

1
@GEMI 그냥 호기심에, MAX(DATE)주문 9999에 대해 한 줄을 반환 하지 않습니까?
Zameer

예,하지만 각 다른 주문이 마지막 주문 라인 만 반환하기를 원했습니다.
GEMI

답변:


184

가능하다면 rownumber() over(...)....

select OrderNO,
       PartCode,
       Quantity
from (select OrderNO,
             PartCode,
             Quantity,
             row_number() over(partition by OrderNO order by DateEntered desc) as rn
      from YourTable) as T
where rn = 1      

2
감사합니다 Mikael Eriksson, 이것은 멋진 쿼리입니다!
GEMI

56

ROW_NUMBER()가능한 경우 가장 좋은 방법은 Mikael Eriksson 입니다.

차선책은 Cularis의 답변에 따라 쿼리에 참여하는 것입니다.

또는 가장 간단하고 직접적인 방법은 WHERE 절의 상관 하위 쿼리입니다.

SELECT
  *
FROM
  yourTable AS [data]
WHERE
  DateEntered = (SELECT MAX(DateEntered) FROM yourTable WHERE orderNo = [data].orderNo)

또는...

WHERE
  ID = (SELECT TOP 1 ID FROM yourTable WHERE orderNo = [data].orderNo ORDER BY DateEntered DESC)

29
select OrderNo,PartCode,Quantity
from dbo.Test t1
WHERE EXISTS(SELECT 1
         FROM dbo.Test t2
         WHERE t2.OrderNo = t1.OrderNo
           AND t2.PartCode = t1.PartCode
         GROUP BY t2.OrderNo,
                  t2.PartCode
         HAVING t1.DateEntered = MAX(t2.DateEntered))

이것은 위에 제공된 모든 쿼리 중 가장 빠릅니다. 쿼리 비용은 0.0070668입니다.

Mikael Eriksson이 작성한 위의 기본 답변은 쿼리 비용이 0.0146625입니다.

이러한 작은 샘플의 성능에 관심이 없을 수도 있지만 큰 쿼리에서는 모두 합산됩니다.


2
이것은 ~ 3.5M 행 데이터 세트에서 다른 솔루션보다 약간 더 빠르지 만 SSMS는 실행 시간을 절반으로 줄이는 인덱스를 제안했습니다. 감사!
easuter

빠르고 간단합니다. 감사.
Stephen Zeng 2015

10 만 개의 행이 있고 Mikael Eriksson의 쿼리가 3 배 더 빠릅니다. 아마도 절로 파티션에 ROUND 기능이 있기 때문일 수 있습니다.
Wachburn

2 개의 다른 ID에 대해 동일한 값 (
2017

예 Portekoi, 맞습니다.하지만 두 행을 구별하는 다른 방법이 없는데 어떻게 하나를 다른 행보다 선택할 수 있습니까? 결과에 TOP을 넣을 수 있지만 원하는 다른 행이 아니라는 것을 어떻게 알 수 있습니까?

10
SELECT t1.OrderNo, t1.PartCode, t1.Quantity
FROM table AS t1
INNER JOIN (SELECT OrderNo, MAX(DateEntered) AS MaxDate
            FROM table
            GROUP BY OrderNo) AS t2
ON (t1.OrderNo = t2.OrderNo AND t1.DateEntered = t2.MaxDate)

내부 쿼리는 OrderNo최대 날짜로 모두 선택합니다 . 테이블의 다른 열을 얻으려면, 당신은 그들에 가입 할 수 있습니다 OrderNoMaxDate.


1

MySql의 경우 다음과 같은 작업을 수행 할 수 있습니다.

select OrderNO, PartCode, Quantity from table a
join (select ID, MAX(DateEntered) from table group by OrderNO) b on a.ID = b.ID

주문 번호로 그룹화하면 내부 테이블에서 ID를 선택할 수 없습니다.
Jacob

@Dems 감사 @ 예 cularis,이 MySQL로 언급하고, 질문은 어떤 데이터베이스 엔진 지정하지 않은
bencobb

당신이 포스트 코드, XML 또는 데이터 샘플, 경우 하시기 바랍니다 텍스트 편집기에서 그 라인을 강조하고 "코드 샘플"버튼 (클릭 { }친절에 편집기 도구 모음) 형식 및 구문을 강조!
marc_s

이것은 MSSQL입니다. 죄송합니다.
GEMI

1

그리고 u는 해당 select 문을 왼쪽 조인 쿼리로 사용할 수도 있습니다. 예 :

... left join (select OrderNO,
   PartCode,
   Quantity from (select OrderNO,
         PartCode,
         Quantity,
         row_number() over(partition by OrderNO order by DateEntered desc) as rn
  from YourTable) as T where rn = 1 ) RESULT on ....

이것이 이것을 찾는 누군가를 돕기를 바랍니다 :)


1

rownumber () over (...)는 작동하지만 두 가지 이유로이 솔루션이 마음에 들지 않았습니다. -SQL2000과 같은 이전 버전의 SQL을 사용하는 경우에는이 기능을 사용할 수 없습니다.

또 다른 해결책은 다음과 같습니다.

SELECT tmpall.[OrderNO] ,
       tmpall.[PartCode] ,
       tmpall.[Quantity] ,
FROM   (SELECT [OrderNO],
               [PartCode],
               [Quantity],
               [DateEntered]
        FROM   you_table) AS tmpall
       INNER JOIN (SELECT [OrderNO],
                          Max([DateEntered]) AS _max_date
                   FROM   your_table
                   GROUP  BY OrderNO ) AS tmplast
               ON tmpall.[OrderNO] = tmplast.[OrderNO]
                  AND tmpall.[DateEntered] = tmplast._max_date

1

ID와 OrderNo를 인덱싱 한 경우 IN을 사용할 수 있습니다. (저는 일부주기를 절약하기 위해 모호함을 위해 거래 단순성을 싫어합니다) :

select * from myTab where ID in(select max(ID) from myTab group by OrderNo);

0

IN 사용 JOIN을 피하십시오

SELECT SQL_CALC_FOUND_ROWS *  FROM (SELECT  msisdn, callid, Change_color, play_file_name, date_played FROM insert_log
   WHERE play_file_name NOT IN('Prompt1','Conclusion_Prompt_1','silent')
 ORDER BY callid ASC) t1 JOIN (SELECT MAX(date_played) AS date_played FROM insert_log GROUP BY callid) t2 ON t1.date_played=t2.date_played

1
왜 IN을 피합니까? 자신의 의견을 뒷받침 할 주장이 있습니까?
Preza8 2018 년

쿼리를 실행하는 데 시간이 오래 걸립니다. 당신은 기사가 다음 읽을 수 xaprb.com/blog/2006/06/28/why-large-in-clauses-are-problematic
왕 네오

@anik 이것은 2006 년의 기사입니다. 당신이 말하는 것에 대한 최근 증거가 있습니까?
Félix Gagnon-Grenier

0

이것은 나를 위해 완벽하게 잘 작동했습니다.

    select name, orderno from (
         select name, orderno, row_number() over(partition by 
           orderno order by created_date desc) as rn from orders
    ) O where rn =1;

-1

이것은 나를 위해 작동합니다. 사용 MAX는 (CONVERT (날짜, ReportDate)) 당신이 날짜 값을 가지고 있는지 확인하기

select max( CONVERT(date, ReportDate)) FROM [TraxHistory]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.