SQL Server:MAX(DATE)の行のみをSELECT


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に対して1行だけが返されたことに注意してください。

ありがとう!


2
コメントから、ROW_NUMBER()の回答を使用してください。見た目は長くなるかもしれませんが、私の経験では、適切なインデックスを使用した方がはるかに高速です。
MatBailie、2011

Demsに感謝します。あなたの努力に感謝します。
GEMI 2011

1
@GEMIは好奇心が足りませんMAX(DATE)。注文9999に対して1行を返しませんか?
Zameer 2016年

はい、しかし、私はそれぞれの異なる注文が最後の注文明細のみを返すことを望みました。
GEMI 2016

回答:


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 2011

56

ROW_NUMBER()可能な場合は、ミカエルエリクソンが最善の方法です。

次善の策は、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
これは、ここまでの350万行のデータセットの他のソリューションよりもわずかに速いことがわかりましたが、SSMSは実行時間を半分に短縮するインデックスを提案しました。ありがとう!
イースター

高速かつ簡単です。ありがとう。
Stephen Zeng

10万行あり、Mikael Erikssonのクエリは3倍速くなりました。多分それは私がpartition by句にROUND関数を持っているためです。
Wachburn

2つの異なるIDに対して同じ値(
2017

はい、Portekoi、それは本当ですが、2つの行を区別する他の方法がない場合、どのようにして一方を他方から選択できますか?結果に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は、最大日付のすべてを選択します。テーブルの他の列を取得するには、それらをOrderNoとで結合しますMaxDate


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を選択することはできません注文番号によってあなたのグループの場合
ジェイコブ

@Dems thanks @ cularisはい、これはMySqlを参照しています。質問ではどのデータベースエンジンを指定していませんでした
bencobb

コード、XML、またはデータサンプルを投稿する場合は、テキストエディターでそれらの行強調表示{ }し、エディターのツールバーの[コードサンプル]ボタン()をクリックして、フォーマットと構文を適切に強調表示してください。
marc_s 2011

これはMSSQLです。申し訳ありません。
GEMI 2011

1

そして、その選択ステートメントを左結合クエリとして使用することもできます...例:

... 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(...)は機能していますが、この解決策は2つの理由で気に入りませんでした。-この関数は、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
king neo

@anikこれは2006年の記事です。あなたが言っていることの最近の証拠はありますか?
フェリックス・ガニオン-グルニエ

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.