web-dev-qa-db-ja.com

SQLでグループごとに最後のレコードを取得する方法

私はかなり興味深い問題に直面しています。次の構造を持つテーブルがあります。

CREATE TABLE [dbo].[Event]
(
    Id int IDENTITY(1,1) NOT NULL,
    ApplicationId nvarchar(32) NOT NULL,
    Name nvarchar(128) NOT NULL,
    Description nvarchar(256) NULL,
    Date nvarchar(16) NOT NULL,
    Time nvarchar(16) NOT NULL,
    EventType nvarchar(16) NOT NULL,
    CONSTRAINT Event_PK PRIMARY KEY CLUSTERED ( Id ) WITH (
        PAD_INDEX = OFF, 
        STATISTICS_NORECOMPUTE = OFF, 
        IGNORE_DUP_KEY = OFF, 
        ALLOW_ROW_LOCKS = ON, 
        ALLOW_PAGE_LOCKS  = ON
    )
)

したがって、問題は、このデータをグリッドに表示する必要があることです。 2つの要件があります。 1つ目は、どのアプリケーションがそれらをスローしたかに関係なく、すべてのイベントを表示することです。これは簡単です-選択ステートメントは非常に簡単に仕事をします。

2番目の要件は、Applicationでイベントをグループ化できることです。言い換えると、ApplicationIdが複数回繰り返された場合に、すべてのアプリケーションの最後のエントリのみを取得するように、すべてのイベントを表示します。この時点でのイベントの主キー(Id)は、このクエリ/ビューでは不要になりました。

また、イベントの日付と時刻が文字列形式であることに気付くかもしれません。これは、標準の日付/時刻形式(mm/dd/yyyyおよびhh:mm:ss)に従うため、問題ありません。私は次のようにそれらを引き出すことができます:

Convert( DateTime, (Date + ' ' +  Time)) AS 'TimeStamp'

私の問題は、残りの列でAGGREGATE関数を使用した場合、どのように動作するかわからないことです。

SELECT
    ApplicationId,
    MAX(Name),
    MAX(Description),
    MAX( CONVERT(DateTime, (Date + ' ' + Time))) AS 'TimeStamp',
    MAX( EventType )
FROM
    Event
GROUP BY
    ApplicationId

私がそうするのをためらう理由は、MAXなどの関数が、レコードの(サブセット)セットから特定の列の最大値を返すためです。最後のレコードを引く必要はありません!

アプリケーションごとに最後のレコードのみを選択する方法に関するアイデアはありますか?

24
bleepzter

ランク付け関数 および 共通テーブル式 を使用できます。

WITH e AS
(
     SELECT *,
         ROW_NUMBER() OVER
         (
             PARTITION BY ApplicationId
             ORDER BY CONVERT(datetime, [Date], 101) DESC, [Time] DESC
         ) AS Recency
     FROM [Event]
)
SELECT *
FROM e
WHERE Recency = 1
43
Anthony Faull

SQL Server 2012以降、簡単に

SELECT 
    [Month]
    , [First] = FIRST_VALUE(SUM([Clicks])) OVER (ORDER BY [Month])
    , [Last]  = FIRST_VALUE(SUM([Clicks])) OVER (ORDER BY [Month] DESC)
FROM 
    [dbo].[Table]
GROUP BY [Month]
ORDER BY [Month]
8
tartakynov

6年後、SQL Serverの別の答え:

select t1.[Id], t2.[Value]  
from [dbo].[Table] t1  
  outer apply (  
    select top 1 [Value]  
      from [dbo].[Table] t2  
        where t2.[Month]=t1.[Month]  
      order by [dbo].[Date] desc  
  )  

私はPostgresqlソリューションが好きですが、入力するのに優れており、はるかに効率的な独自のオン機能を備えています:

select distinct on (id),val  
from tbl  
order by id,val  
0
Domagoj Peharda

Group byでサブクエリを使用できます-group by引数はselectにある必要はありません。これは、IDが自動インクリメントされ、最大のものが最新のものであると想定しています。

SELECT
    ApplicationId,
    Name,
    Description,
    CONVERT(DateTime, (Date + ' ' + Time)) AS 'TimeStamp',
    EventType
FROM
    Event e
WHERE
    Id in (select max(Id) from Event GROUP BY ApplicationId)
0
cordsen

私はそれが最後に挿入されたレコードをフェッチするために喜んでそこに多くの人のために働くと思うとそれはグループ化する必要があります:

select * from(select * from TableName ORDER BY id DESC)AS x GROUP BY FieldName

次の場合に機能します。

テーブル構造 ID名前ステータス1 Junaidはい2 Jawadいいえ3 Fahadはい4 Junaidいいえ5 Kashifはい

上記のクエリ後の結果 ID Name Status 4 Junaid No 2 Jawad No 3 Fahad Yes 4 Kashif Yes

名前によるグループの最後のレコードの結果です。

0
smjunaidiqbal
SELECT
    E.ApplicationId,
    E.Name,
    E.Description,
    CONVERT(DateTime, (E.Date + ' ' + E.Time)) AS 'TimeStamp',
    E.EventType
FROM
    Event E
    JOIN (SELECT ApplicationId,
                 MAX(CONVERT(DateTime, (Date + ' ' + Time))) AS max_date
            FROM Event
        GROUP BY ApplicationId) EM 
      on EM.ApplicationId = E.ApplicationId
     and EM.max_date = CONVERT(DateTime, (E.Date + ' ' + E.Time)))
0
manji

そこにはwhere句がないため、レコードのサブセットはすべてのレコードです。しかし、あなたは間違った列に最大値を入れていると思います。このクエリは、あなたが探しているものを提供します。

Select max(applicationid), name, description, CONVERT(DateTime, (Date + ' ' + Time)) 
from event
group by name, description, CONVERT(DateTime, (Date + ' ' + Time)) 
0
Jody

これを行うには、サブクエリまたはCTEテーブルを使用できます。

;WITH CTE_LatestEvents as (
SELECT
    ApplicationId,    
    MAX( CONVERT(DateTime, (Date + ' ' + Time))) AS 'LatestTimeStamp',
FROM
    Event
GROUP BY
    ApplicationId
)
SELECT
    ApplicationId,
    Name,
    Description,
    CONVERT(DateTime, (Date + ' ' + Time))) AS 'TimeStamp',
    EventType
FROM
    Event e
    Join CTE_LatestEvents le 
        on e.applicationid = le.applicationid
        and CONVERT(DateTime, (e.Date + ' ' + e.Time))) = le.LatestTimeStamp
0
Jon Egerton