各ユーザーの最新の記録日を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-Server、Oracle、...?
Peter Lang

1
最新の日付と一致する値、または最大値と最大日付が必要ですか?
マシュージョーンズ

回答:


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
マルコ・ロイ

@RedFilterこれは私の問題に最適です。そのような技術的な質問をたくさんありがとう。私は特定の日付の複数の結果を避けるために代わりの日付の日時を使用ところで
ムハンマド・ハーン

なぜ「そして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
ピエレバント

2
このアプローチの大きな利点は、パーティションごとに常に1行だけが返されることが保証され(usernameこの場合)、一意の「順序付け可能な」フィールドさえ必要としないことです(max(date)他の回答に参加するなど)。
マルコ・ロイ

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は機能しません。つまり、一般的な解決策ではありませんが、LEFT OUTER JOINを使用するという考え方が重要ですこの答えの中のもの。
iversoncru

興味深いことに、Sybase ASE 16は小さい(1万行未満)テーブルでは正常に機能しますが、大きい(10万行以上)テーブルではハングします...これは、リレーショナル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はOracleのin句で遅く、インデックスを使用しません
meadlai

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

4
これは別の可能な解決策ですが、これは通常これを解決する良い方法ではありません。この方法でこれを行うと、テーブル内の名前ごとに内部クエリが1回実行され、サイズが大きいテーブルでは大幅な速度低下が発生します。where句の最初のクエリの要素を持たない別のクエリを実行すると、通常は2つのテーブルが結合されます。
スコットチェンバレン

これには、実装固有ではない、より理解しやすいソリューションの1つであるという優れた機能があります。
Michael Szczepaniak

7

私の経験から、最も速い方法は、テーブルに新しい行がない各行を取得することです。

もう1つの利点は、使用される構文が非常にシンプルであり、クエリの意味がかなり理解しやすいことです(検討中のユーザー名に新しい行が存在しないようにすべての行を取得します)。

存在しない

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件のレコードを取得する必要があります。内部クエリでは、ユーザー名で照合することもできますか?
Narshe

それは次のように使用して私の作品: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が結合を処理します。同じユーザーの同じ日付のエントリが2つある場合、最も高いエントリが返され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、2015

ユーザー名でグループ化しているため、機能し、結果は次のようになります。ユーザー名日付値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
実装または説明に関する1〜2文は、質の高い回答を作成するのに大いに役立ちます。

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へようこそ。ご協力いただきありがとうございます。あなたのようなコードのみの回答は、解決策を説明する回答と比較するとあまり評価されません。
ユンノシュ

質の高い回答を提供するにはこのハウツーの回答をお読みください。
2017年

そして。ユーザー名ごとにMAXに戻るのではなく、最新の単一行に戻ります。
IrvineCAGuy 2018

0

私の小さな編集

  • joinネストより自己select
  • しかし、それはgroup byあなたprimary keyに与えられませんjoin
  • このキーは(docspartition byと組み合わせて指定できますfirst_value

だから、ここにクエリがあります:

選択する
 t。*
から 
 テーブルt内部結合(
  IDとして、(GroupColumnによるパーティション、DateColumn descによるパーティション)を区別するfirst_value(ID)を選択します。
  テーブルから
  ここでFilterColumn = 'value'
 )j on t.ID = 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

これは上記の回答の1つに似ていますが、私の意見では、はるかに単純で整然としています。また、クロス適用ステートメントの適切な使用法を示しています。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
編集ではvalueMAX(date)行に関連付けられているものではなく、ランダムなものが選択されます。
アリソンR.

最大日付が表示されますが、ユーザー名と値は同じレコードではない可能性があります。
SKR
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.