各グループの上位1行を取得する


530

各グループの最新のエントリを取得したいテーブルがあります。これがテーブルです:

DocumentStatusLogs テーブル

|ID| DocumentID | Status | DateCreated |
| 2| 1          | S1     | 7/29/2011   |
| 3| 1          | S2     | 7/30/2011   |
| 6| 1          | S1     | 8/02/2011   |
| 1| 2          | S1     | 7/28/2011   |
| 4| 2          | S2     | 7/30/2011   |
| 5| 2          | S3     | 8/01/2011   |
| 6| 3          | S1     | 8/02/2011   |

テーブルはグループ化さDocumentIDDateCreated、降順で並べ替えられます。それぞれについてDocumentID、最新のステータスを取得したいと思います。

私の好ましい出力:

| DocumentID | Status | DateCreated |
| 1          | S1     | 8/02/2011   |
| 2          | S3     | 8/01/2011   |
| 3          | S1     | 8/02/2011   |
  • 各グループからトップのみを取得する集計関数はありますか?GetOnlyTheTop以下の疑似コードを参照してください。

    SELECT
      DocumentID,
      GetOnlyTheTop(Status),
      GetOnlyTheTop(DateCreated)
    FROM DocumentStatusLogs
    GROUP BY DocumentID
    ORDER BY DateCreated DESC
    
  • そのような機能が存在しない場合、私が望む出力を達成する方法はありますか?

  • または、そもそも、これは正規化されていないデータベースが原因である可能性がありますか?私が探しているのは1行だけなので、それstatusも親テーブルにあるべきですか?

詳細については、親の表をご覧ください。

現在のDocumentsテーブル

| DocumentID | Title  | Content  | DateCreated |
| 1          | TitleA | ...      | ...         |
| 2          | TitleB | ...      | ...         |
| 3          | TitleC | ...      | ...         |

親テーブルはこのようにして、ステータスに簡単にアクセスできるようにする必要がありますか?

| DocumentID | Title  | Content  | DateCreated | CurrentStatus |
| 1          | TitleA | ...      | ...         | s1            |
| 2          | TitleB | ...      | ...         | s3            |
| 3          | TitleC | ...      | ...         | s1            |

更新 私は、「適用」を使用してそのような問題に簡単に対処する方法を学びました。


2
可能な解決策のより詳細な説明と比較については、dba.seで同様の質問を読むことをお勧めします:グループごとにn行を取得します。
Vladimir Baranov 2016年

投稿を見て試してみました。StoreIDによるグループを使用すると、エラーが発生しました。
UltraJ

回答:


757
;WITH cte AS
(
   SELECT *,
         ROW_NUMBER() OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC) AS rn
   FROM DocumentStatusLogs
)
SELECT *
FROM cte
WHERE rn = 1

1日に2つのエントリが予想される場合、これは任意に1つを選択します。1日の両方のエントリを取得するには、代わりにDENSE_RANKを使用します

正規化されているかどうかについては、次のことを行うかどうかによって異なります。

  • 2か所でステータスを維持する
  • ステータス履歴を保持する
  • ...

現状では、ステータス履歴を保持します。親テーブルでも最新のステータスが必要な場合(これは非正規化です)、親で「ステータス」を維持するトリガーが必要になります。または、このステータス履歴テーブルを削除します。


5
そして...何Partition Byですか?Withまた、私には新しいものである:(私はとにかくMSSQL 2005を使用しています。
DPP

6
@domanokz:Partition Byはカウントをリセットします。したがって、この場合、DocumentIDごとにカウントするように言われています
gbn

1
うーん、パフォーマンスを心配しているので、何百万もの行をクエリします。SELECT * FROM(SELECT ...)はパフォーマンスに影響しますか?また、ROW_NUMBER各行に何らかのサブクエリがありますか?
dpp

1
@domanokz:いいえ、サブクエリではありません。正しいインデックスがあれば、何百万もの問題はないはずです。いずれにせよ、2つのセットベースの方法があります:これと集計(アリエルのソリューション)両方試してみてください
gbn

1
@domanokz:ORDER BY DateCreated DESCをORDER BY ID DESCに変更する
gbn

184

使い方を覚えましたcross apply。このシナリオでの使用方法は次のとおりです。

 select d.DocumentID, ds.Status, ds.DateCreated 
 from Documents as d 
 cross apply 
     (select top 1 Status, DateCreated
      from DocumentStatusLogs 
      where DocumentID = d.DocumentId
      order by DateCreated desc) as ds

2
この問題はまだ解決されていないため、実際には違いはありません。
dpp

19
提案されたすべてのソリューションに対するタイミングテストの結果を投稿したところ、あなたのソリューションがトップになりました。あなたに賛成票を与える:-)
ジョンフェアバンクス

3
速度を大幅に向上させるための+1。これは、ROW_NUMBER()などのウィンドウ関数よりもはるかに高速です。SQLがクエリと同様にROW_NUMBER()= 1を認識し、それらをAppliesに最適化するとよいでしょう。注:必要な結果が得られなかった場合でも、必要に応じてOUTER APPLYを使用しました。
TamusJRoyce、2015年

8
@TamusJRoyceこれが常に当てはまると高速だったからといって、それを推定することはできません。場合によります。ここで説明するように、sqlmag.com / database
Martin Smith

2
私のコメントは、複数の行を持つこと、およびグループごとにそれらの複数の行の1つだけを希望することについてです。結合は、1対多の場合に使用します。1対多の場合に適用されますが、1対1を除くすべてを除外します。シナリオ:100人のメンバーの場合、それぞれに最高の電話番号(それぞれに複数の番号が含まれる可能性があります)を教えてください。これは、Applyが優れている点です。読み取りが少ない=ディスクアクセスが少ない=パフォーマンスが向上します。私の経験を考えると、不十分に設計された非正規化データベースを使用しています。
TamusJRoyce 2016年

53

私はここでさまざまな推奨事項についていくつかのタイミングをとりましたが、結果は実際に関係するテーブルのサイズに依存しますが、最も一貫した解決策はCROSS APPLYを使用することですこれらのテストはSQL Server 2008-R2に対して実行され、 6,500レコード、および1億3700万レコードの別の(同一スキーマ)。照会される列はテーブルの主キーの一部であり、テーブルの幅は非常に小さい(約30バイト)。時間は、SQL Serverによって実際の実行計画から報告されます。

Query                                  Time for 6500 (ms)    Time for 137M(ms)

CROSS APPLY                                    17.9                17.9
SELECT WHERE col = (SELECT MAX(COL)…)           6.6               854.4
DENSE_RANK() OVER PARTITION                     6.6               907.1

本当に驚くべきことは、関係する行の数に関係なく、CROSS APPLYの時間がどれほど一貫していたかでした。


8
それはすべてデータの分布と利用可能なインデックスに依存します。dba.seでかなり長く議論されました
Vladimir Baranov 2016年

48

私はこれが古いスレッドであることを知っていますが、TOP 1 WITH TIES解決策は非常に優れており、解決策を読むのに役立つかもしれません。

select top 1 with ties
   DocumentID
  ,Status
  ,DateCreated
from DocumentStatusLogs
order by row_number() over (partition by DocumentID order by DateCreated desc)

TOP句の詳細については、こちらをご覧ください


7
これは最もエレガントなソリューション
imoです

1
合意された-非常に簡単芋SQLおよび他の言語の他のバージョンで行うことです何この最高の反復
クリスUmphlett

27

パフォーマンスが心配な場合は、MAX()を使用してこれを行うこともできます。

SELECT *
FROM DocumentStatusLogs D
WHERE DateCreated = (SELECT MAX(DateCreated) FROM DocumentStatusLogs WHERE ID = D.ID)

ROW_NUMBER()はSELECTステートメントのすべての行の一種を必要としますが、MAXは必要としません。クエリを大幅に高速化する必要があります。


2
ROW_NUMBER()のパフォーマンスの問題は、適切なインデックス付けで対処できませんか?(とにかくそれを行う必要があると思います)
クリストファーL

8
datetimeでは、同じ日付と時刻に2つのエントリが追加されないことを保証できません。精度が十分ではありません。
TamusJRoyce、2015年

単純化のために+1。@TamusJRoyceは正しいです。どうですか?'select * from DocumentStatusLog D where ID =(select ID from DocumentsStatusLog where D.DocumentID = DocumentID order by DateCreated DESC limit 1);'
cibercitizen1 2017年

SELECT * FROM EventScheduleTbl D WHERE DatesPicked =(SELECT top 1 min(DatesPicked)FROM EventScheduleTbl WHERE EventIDf = D.EventIDf and DatesPicked> = convert(date、getdate()))
Arun Prasad ES

row_number()適切なインデックス作成を行っても、これよりもパフォーマンスが優れている場合があります。自己結合のシナリオでは特に価値があると思います。ただし、この方法では、サブツリーのコストが低いと報告されているにもかかわらず、多くの場合、論理読み取りとスキャンカウントの両方の数が多くなります。実際の方が優れているかどうかを判断するには、特定のケースのコスト/メリットを比較検討する必要があります。
pimbrouwers 2018

26
SELECT * FROM
DocumentStatusLogs JOIN (
  SELECT DocumentID, MAX(DateCreated) DateCreated
  FROM DocumentStatusLogs
  GROUP BY DocumentID
  ) max_date USING (DocumentID, DateCreated)

どのデータベースサーバー?このコードはそれらすべてで機能しません。

質問の後半については、ステータスを列として含めるのが理にかなっています。DocumentStatusLogsログとして残しておいても、メインテーブルに最新の情報を保存できます。

ところで、すでにDateCreatedDocumentsテーブルに列がある場合は、それをDocumentStatusLogs使用して結合できます(DateCreatedで一意である限りDocumentStatusLogs)。

編集:MsSQLはUSINGをサポートしていないため、次のように変更します。

ON DocumentStatusLogs.DocumentID = max_date.DocumentID AND DocumentStatusLogs.DateCreated = max_date.DateCreated

5
手がかりはタイトルにありました:MSSQL。SQL ServerにはUSINGがありませんが、アイデアはOKです。
gbn 2011

7
@gbn愚かなモデレーターは通常、ここで行ったように、タイトルから重要なキーワードを削除します。検索結果やGoogleで正しい答えを見つけるのが非常に困難になります。
NickG

2
あなたは上のネクタイ持っている場合は、この「ソリューション」は、まだあなたに複数のレコードを与えることができることを指摘する強行max(DateCreated)
MoonKnight

12

これはこのトピックで最も簡単に見つけられる質問の1つなので、私はそれに対して現代的な答えを出したいと思いました(参照用と他の人を助けるための両方)。使用するfirst_valueover、あなたは上記のクエリの短編作品を作ることができます。

Select distinct DocumentID
  , first_value(status) over (partition by DocumentID order by DateCreated Desc) as Status
  , first_value(DateCreated) over (partition by DocumentID order by DateCreated Desc) as DateCreated
From DocumentStatusLogs

これはSQL Server 2008以降で機能するはずです。節を使用するときFirst_valueに達成する方法として考えることができます。選択リストでグループ化できるため、ネストされたサブクエリを書く代わりに(既存の回答の多くがそうであるように)、これはより読みやすい方法でそれを行います。お役に立てれば。Select Top 1overOver


2
これはSQL Server 2008 R2では機能しません。first_valueは2012年に導入されたと思います。
ufo 2018年

1
とても早い!@dppが提供するクロスアプライソリューションを使用していましたが、こちらの方が高速です。
MattSlay

11

これはかなり古いスレッドですが、受け入れられた回答が特にうまく機能しなかったのと同じように、2セントを投入すると思いました。大規模なデータセットでgbnのソリューションを試したところ、ひどく遅い(SQL Server 2012の500万以上のレコードで45秒を超える)ことがわかりました。実行計画を見ると、問題がSORT操作を必要としているため、処理速度が大幅に低下していることが明らかです。

SORT操作を必要とせず、非クラスター化インデックス検索を実行するエンティティフレームワークから私が持ち上げた代替案を次に示します。これにより、前述のレコードセットの実行時間が2秒未満に短縮されます。

SELECT 
[Limit1].[DocumentID] AS [DocumentID], 
[Limit1].[Status] AS [Status], 
[Limit1].[DateCreated] AS [DateCreated]
FROM   (SELECT DISTINCT [Extent1].[DocumentID] AS [DocumentID] FROM [dbo].[DocumentStatusLogs] AS [Extent1]) AS [Distinct1]
OUTER APPLY  (SELECT TOP (1) [Project2].[ID] AS [ID], [Project2].[DocumentID] AS [DocumentID], [Project2].[Status] AS [Status], [Project2].[DateCreated] AS [DateCreated]
    FROM (SELECT 
        [Extent2].[ID] AS [ID], 
        [Extent2].[DocumentID] AS [DocumentID], 
        [Extent2].[Status] AS [Status], 
        [Extent2].[DateCreated] AS [DateCreated]
        FROM [dbo].[DocumentStatusLogs] AS [Extent2]
        WHERE ([Distinct1].[DocumentID] = [Extent2].[DocumentID])
    )  AS [Project2]
    ORDER BY [Project2].[ID] DESC) AS [Limit1]

今、私は元の質問で完全に指定されていないものを想定していますが、テーブルのデザインがID列が自動インクリメントIDであり、DateCreatedが挿入ごとに現在の日付に設定されている場合は、上記の私のクエリを使用せずに実行すると、DateCreatedで並べ替えるのではなく、IDで並べ替えるだけでgbnのソリューション(実行時間の約半分)を大幅に向上させることができます。


5

各グループからトップ1を選択するためのコード

#DocumentStatusLogsからa。*を選択します 
 datecreated in(#DocumentStatusLogs bから上位1件のdatecreatedを選択します
どこ 
a.documentid = b.documentid
日付順で作成
)

3

上からクリントの素晴らしいと正しい答えを確認します:

以下の2つのクエリ間のパフォーマンスは興味深いものです。52%がトップです。そして48%が2番目のものです。ORDER BYの代わりにDISTINCTを使用すると、パフォーマンスが4%向上します。ただし、ORDER BYには、複数の列でソートするという利点があります。

IF (OBJECT_ID('tempdb..#DocumentStatusLogs') IS NOT NULL) BEGIN DROP TABLE #DocumentStatusLogs END

CREATE TABLE #DocumentStatusLogs (
    [ID] int NOT NULL,
    [DocumentID] int NOT NULL,
    [Status] varchar(20),
    [DateCreated] datetime
)

INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (2, 1, 'S1', '7/29/2011 1:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (3, 1, 'S2', '7/30/2011 2:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (6, 1, 'S1', '8/02/2011 3:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (1, 2, 'S1', '7/28/2011 4:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (4, 2, 'S2', '7/30/2011 5:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (5, 2, 'S3', '8/01/2011 6:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (6, 3, 'S1', '8/02/2011 7:00:00')

オプション1:

    SELECT
    [Extent1].[ID], 
    [Extent1].[DocumentID],
    [Extent1].[Status], 
    [Extent1].[DateCreated]
FROM #DocumentStatusLogs AS [Extent1]
    OUTER APPLY (
        SELECT TOP 1
            [Extent2].[ID], 
            [Extent2].[DocumentID],
            [Extent2].[Status], 
            [Extent2].[DateCreated]
        FROM #DocumentStatusLogs AS [Extent2]
        WHERE [Extent1].[DocumentID] = [Extent2].[DocumentID]
        ORDER BY [Extent2].[DateCreated] DESC, [Extent2].[ID] DESC
    ) AS [Project2]
WHERE ([Project2].[ID] IS NULL OR [Project2].[ID] = [Extent1].[ID])

オプション2:

SELECT 
    [Limit1].[DocumentID] AS [ID], 
    [Limit1].[DocumentID] AS [DocumentID], 
    [Limit1].[Status] AS [Status], 
    [Limit1].[DateCreated] AS [DateCreated]
FROM (
    SELECT DISTINCT [Extent1].[DocumentID] AS [DocumentID] FROM #DocumentStatusLogs AS [Extent1]
) AS [Distinct1]
    OUTER APPLY  (
        SELECT TOP (1) [Project2].[ID] AS [ID], [Project2].[DocumentID] AS [DocumentID], [Project2].[Status] AS [Status], [Project2].[DateCreated] AS [DateCreated]
        FROM (
            SELECT 
                [Extent2].[ID] AS [ID], 
                [Extent2].[DocumentID] AS [DocumentID], 
                [Extent2].[Status] AS [Status], 
                [Extent2].[DateCreated] AS [DateCreated]
            FROM #DocumentStatusLogs AS [Extent2]
            WHERE [Distinct1].[DocumentID] = [Extent2].[DocumentID]
        )  AS [Project2]
        ORDER BY [Project2].[ID] DESC
    ) AS [Limit1]

M $のManagement Studio:最初のブロックを強調表示して実行した後、オプション1とオプション2の両方を強調表示します。右クリック-> [推定実行計画を表示]をクリックします。次に、全体を実行して結果を確認します。

オプション1の結果:

ID  DocumentID  Status  DateCreated
6   1   S1  8/2/11 3:00
5   2   S3  8/1/11 6:00
6   3   S1  8/2/11 7:00

オプション2の結果:

ID  DocumentID  Status  DateCreated
6   1   S1  8/2/11 3:00
5   2   S3  8/1/11 6:00
6   3   S1  8/2/11 7:00

注意:

結合を1対(1対多)にしたい場合は、APPLYを使用する傾向があります。

結合を1対多または多対多にする場合は、JOINを使用します。

私は、ROW_NUMBER()を使用してCTEを回避します。ただし、高度な処理を行う必要があり、ウィンドウパフォーマンスのペナルティに問題がない場合を除きます。

また、WHERE句またはON句でEXISTS / INサブクエリを使用しないようにしています。しかし、走行距離は異なります。実行計画を確認し、必要に応じてパフォーマンスをプロファイルします!


3

このソリューションを使用して、各パーティションの最新の上位N行を取得できます(この例では、WHEREステートメントのNは1で、パーティションはdoc_idです)。

SELECT doc_id, status, date_created FROM 
(
    SELECT a.*, ROW_NUMBER() OVER (PARTITION BY doc_id ORDER BY date_created DESC) AS rnk FROM doc a
)
WHERE rnk = 1;

2
SELECT o.*
FROM `DocumentStatusLogs` o                   
  LEFT JOIN `DocumentStatusLogs` b                   
  ON o.DocumentID = b.DocumentID AND o.DateCreated < b.DateCreated
 WHERE b.DocumentID is NULL ;

DateCreatedによる最近のドキュメントの順序のみを返す場合、DocumentIDによる上位1つのドキュメントのみを返します。


2

CROSS APPLYそれは私のために、そして私のクライアントのニーズのために機能したので、私が私のソリューションに使用した方法でした。そして、私が読んだことから、データベースが大幅に拡大しても、全体的なパフォーマンスが最高になるはずです。


1

ここでは、問題への3つの個別のアプローチと、各クエリのインデックス作成の最良の選択を示します(自分でインデックスを試して、論理的な読み取り、経過時間、実行計画を確認してください。この特定の問題のために実行することなくそのようなクエリ)。

アプローチ1:ROW_NUMBER()を使用します。行ストアインデックスでパフォーマンスを向上させることができない場合は、非クラスター化/クラスター化列ストアインデックスを試すことができます。これは、集計とグループ化を使用したクエリや、さまざまな列で常に順序付けられているテーブルの場合、列ストアインデックスが通常最良の選択です。

;WITH CTE AS
    (
       SELECT   *,
                RN = ROW_NUMBER() OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC)
       FROM     DocumentStatusLogs
    )
    SELECT  ID      
        ,DocumentID 
        ,Status     
        ,DateCreated
    FROM    CTE
    WHERE   RN = 1;

アプローチ2:FIRST_VALUEを使用します。行ストアインデックスでパフォーマンスを向上させることができない場合は、非クラスター化/クラスター化列ストアインデックスを試すことができます。これは、集計とグループ化を使用したクエリや、さまざまな列で常に順序付けられているテーブルの場合、列ストアインデックスが通常最良の選択です。

SELECT  DISTINCT
    ID      = FIRST_VALUE(ID) OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC)
    ,DocumentID
    ,Status     = FIRST_VALUE(Status) OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC)
    ,DateCreated    = FIRST_VALUE(DateCreated) OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC)
FROM    DocumentStatusLogs;

アプローチ3:CROSS APPLYを使用する。クエリで使用される列をカバーするDocumentStatusLogsテーブルに行ストアインデックスを作成すると、列ストアインデックスがなくてもクエリをカバーできます。

SELECT  DISTINCT
    ID      = CA.ID
    ,DocumentID = D.DocumentID
    ,Status     = CA.Status 
    ,DateCreated    = CA.DateCreated
FROM    DocumentStatusLogs D
    CROSS APPLY (
            SELECT  TOP 1 I.*
            FROM    DocumentStatusLogs I
            WHERE   I.DocumentID = D.DocumentID
            ORDER   BY I.DateCreated DESC
            ) CA;

1

これはこのようにできると思います。これには多少の調整が必要になる場合がありますが、グループから最大値を選択するだけで済みます。

これらの答えはやりすぎです。

SELECT
  d.DocumentID,
  MAX(d.Status),
  MAX(d1.DateCreated)
FROM DocumentStatusLogs d, DocumentStatusLogs d1
USING(DocumentID)
GROUP BY d.DocumentID
ORDER BY DateCreated DESC

0

row_count()の使用を避けたいシナリオでは、左結合も使用できます。

select ds.DocumentID, ds.Status, ds.DateCreated 
from DocumentStatusLogs ds
left join DocumentStatusLogs filter 
    ON ds.DocumentID = filter.DocumentID
    -- Match any row that has another row that was created after it.
    AND ds.DateCreated < filter.DateCreated
-- then filter out any rows that matched 
where filter.DocumentID is null 

スキーマの例では、「not in subquery」を使用することもできます。これは通常、左結合と同じ出力にコンパイルされます。

select ds.DocumentID, ds.Status, ds.DateCreated 
from DocumentStatusLogs ds
WHERE ds.ID NOT IN (
    SELECT filter.ID 
    FROM DocumentStatusLogs filter
    WHERE ds.DocumentID = filter.DocumentID
        AND ds.DateCreated < filter.DateCreated)

テーブルに単一列の一意のキー/制約/インデックスが1つもない場合、サブクエリパターンは機能しません。この場合、主キーは「Id」です。

これらのクエリはどちらも、row_count()クエリ(クエリアナライザーで測定)よりも「高価」になる傾向があります。ただし、結果が早く返される、または他の最適化が有効になるシナリオが発生する可能性があります。


0
SELECT documentid, 
       status, 
       datecreated 
FROM   documentstatuslogs dlogs 
WHERE  status = (SELECT status 
                 FROM   documentstatuslogs 
                 WHERE  documentid = dlogs.documentid 
                 ORDER  BY datecreated DESC 
                 LIMIT  1) 

0

これを試して:

SELECT [DocumentID]
    ,[tmpRez].value('/x[2]', 'varchar(20)') AS [Status]
    ,[tmpRez].value('/x[3]', 'datetime') AS [DateCreated]
FROM (
    SELECT [DocumentID]
        ,cast('<x>' + max(cast([ID] AS VARCHAR(10)) + '</x><x>' + [Status] + '</x><x>' + cast([DateCreated] AS VARCHAR(20))) + '</x>' AS XML) AS [tmpRez]
    FROM DocumentStatusLogs
    GROUP BY DocumentID
    ) AS [tmpQry]

SQLステートメントがどのように機能し、OPのクエリを解決するかを常に説明する必要があります。
スラジクマール

-1

これは私が思いつくことができる最も一般的なTSQLです

    SELECT * FROM DocumentStatusLogs D1 JOIN
    (
      SELECT
        DocumentID,MAX(DateCreated) AS MaxDate
      FROM
        DocumentStatusLogs
      GROUP BY
        DocumentID
    ) D2
    ON
      D2.DocumentID=D1.DocumentID
    AND
      D2.MaxDate=D1.DateCreated

残念ながらMaxDateは一意ではありません。2つの日付を正確に同時に入力することができます。そのため、グループごとに重複が発生する可能性があります。ただし、ID列またはGUIDを使用できます。ID列は、入力された最新のIDを取得します(デフォルトのID計算が使用されています。1... xステップ1)。
TamusJRoyce、2015年

さて、私は一種の同意するが、著者は最新のエントリを求めた-あなたは自動インクリメントID列の手段を含んでいない限り正確に同じ時刻に追加した2つのアイテムは、同じように「最新」である
豊富秒

最新のレコードは1レコードになります。あ、はい。自動インクリメントID列を考慮する必要があります。
TamusJRoyce 2017年

-2

SQLiteでは、次の単純なクエリをGROUP BYで使用できることが確認されています

SELECT MAX(DateCreated), *
FROM DocumentStatusLogs
GROUP BY DocumentID

ここでMAXは、各グループから最大のDateCreatedを取得するのに役立ちます。

しかし、MYSQLは* -columnsをmax DateCreated :(の値に関連付けません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.