webentwicklung-frage-antwort-db.com.de

So erhalten Sie den letzten Datensatz pro Gruppe in SQL

Ich stehe vor einem ziemlich interessanten Problem. Ich habe eine Tabelle mit folgender Struktur:

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
    )
)

Das Problem ist also, dass ich diese Daten in einem Raster anzeigen muss. Es gibt zwei Voraussetzungen. Die erste besteht darin, alle Ereignisse anzuzeigen, unabhängig davon, welche Anwendung sie ausgelöst hat. Dies ist einfach - eine select-Anweisung erledigt die Aufgabe sehr leicht.

Die zweite Voraussetzung ist, dass Ereignisse nach Application gruppiert werden können. Mit anderen Worten: Zeigen Sie alle Ereignisse so an, dass sich die ApplicationId mehrmals wiederholt, und zwar für jede Anwendung nur der letzte Eintrag. Der Primärschlüssel des Ereignisses (Id) zu diesem Zeitpunkt wird in dieser Abfrage/Ansicht nicht mehr benötigt.

Möglicherweise stellen Sie auch fest, dass das Datum und die Uhrzeit des Ereignisses im String-Format vorliegen. Dies ist in Ordnung, da sie den Standard-Datumszeitformaten entsprechen: mm/tt/jjjj und hh: mm: ss. Ich kann das wie folgt ziehen:

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

Mein Problem ist, dass ich nicht weiß, wie sie sich verhalten würden, wenn ich AGGREGATE-Funktionen für die restlichen Spalten verwende:

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

Der Grund, warum ich zögerlich bin, ist, dass eine Funktion wie MAX den größten Wert für eine bestimmte Spalte aus einer (Unter-) Menge von Datensätzen zurückgibt. Es ist nicht notwendig, den letzten Datensatz zu ziehen!

Haben Sie Ideen, wie Sie nur den letzten Datensatz pro Anwendung auswählen können?

24
bleepzter

Sie können einen Ranking-Funktions und einen Common-Tabellenausdruck verwenden.

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
42
Anthony Faull

Seit SQL Server 2012 können Sie das einfach

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]
7
tartakynov

Nach 6 Jahren eine weitere Antwort für 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  
  )  

Obwohl ich die Postgresql-Lösung viel besser finde, mit ihrer besonderen Funktion, die schöner zu schreiben ist und viel effizienter ist: 

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

Sie können eine Unterabfrage mit group by verwenden - das Argument group by muss nicht in select enthalten sein. Dies setzt voraus, dass die ID automatisch erhöht wird, so dass die größte die aktuellste ist.

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

Ich denke, es wird für viele da draußen funktionieren, die bereit sind, den zuletzt eingefügten Datensatz abzurufen, und es sollte gruppiert werden durch:

select * from (select * from Tabellenname ORDER BY id DESC) AS x GROUP BY Feldname

Es wird für Folgendes funktionieren:

Tabellenstruktur ID Name Status 1 Junaid Ja 2 Jawad Nein 3 Fahad Ja 4 Junaid Nein 5 Kashif Ja

Ergebnisse nach obiger Abfrage ID Name Status 4 Junaid Nein 2 Jawad Nein 3 Fahad Ja 4 Kashif Ja

Es ergibt sich einfach der letzte Datensatz der Gruppe nach Namen.

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

Da Sie keine Where-Klausel enthalten, besteht die Teilmenge der Datensätze aus allen Datensätzen. Aber ich denke, Sie setzen Max auf die falschen Spalten. Diese Abfrage gibt Ihnen das, wonach Sie suchen.

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

Sie können dazu eine Unterabfrage oder CTE-Tabelle verwenden:

;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