none
Aggregatfunktionen FIRST und LAST RRS feed

  • Frage

  • Guten Tag,

     

    ich glaube, diese Frage wurde zwar schon mehrfach gestellt bzw. beantwortet. Leider konnte ich keine zielführenden Informationen im www finden.

    Ich habe eine sortierte Tabelle mit Messwerten und verschiedenen Zeitintervallen und möchte nach verschiedenen Zeitintervallen den ersten, den größsten, den kleinsten und den letzten Datensatz gruppiert darstellen.

    Eine Beispieltabelle hat folgenden Aufbau: 

    CREATE TABLE [meineTabelle]
    (
    	[ID] [int] IDENTITY(1,1) NOT NULL,
    	[Datum] [date] NULL,
    	[Uhrzeit] [time](0) NULL,
    	[Messwert] [float] NULL,
    ) 
    ON [PRIMARY]
    

    Bis vor kurzem habe ich die Daten noch in MS Access ausgewertet, nun möchte ich aber meinen Datenbestand mit dem SQL Server Express auswerten. Die Aggregatfunktionen FIRST und LAST werden leider in T-SQL nicht unterstützt.

    Könnt Ihr mir einen Anstoß geben, wie ich die oben angegebenen Aggregatfunktionen auch in T-SQL umsetzen kann? Über jewede Hilfe würde ich mich freuen.

    Vielen Dank

     

    Micha

    Montag, 20. Dezember 2010 16:16

Antworten

  • Hallo Micha,

    in Deinem Fall wäre das in etwa:

    SELECT [Datum]
      ,(SELECT TOP (1) 
    		[Messwert]
    		FROM meineTabelle AS t2
    		WHERE t2.Datum = meineTabelle.Datum 
    		-- Uhrzeit aufsteigend sortiert
    		ORDER BY Uhrzeit) AS Erster
    	
      , MAX([Messwert]) as [Max]
      , MIN([Messwert]) as [Min]
      
      ,(SELECT TOP (1) 
    		[Messwert]
    		FROM meineTabelle AS t2
    		WHERE t2.Datum = meineTabelle.Datum 
    		-- Uhrzeit absteigend sortiert
    		ORDER BY Uhrzeit DESC) AS Letzter
    
    -- Alternativ via MIN/MAX(ID)
      ,(SELECT -- TOP (1) 
    		[Messwert]
    		FROM meineTabelle AS t2
    		WHERE t2.Datum = meineTabelle.Datum 
    			AND t2.ID = MIN([meineTabelle].ID)
    		) AS ErsterViaID
    
      ,(SELECT -- TOP (1) 
    		[Messwert]
    		FROM meineTabelle AS t2
    		WHERE t2.Datum = meineTabelle.Datum 
    			AND t2.ID = MAX([meineTabelle].ID)
    		) AS LetzterViaID
    
    FROM [meineTabelle] 
    GROUP BY [Datum]
    GO
    
    

    Wobei ich zwei Varianten eingebaut habe:
    Einmal über die Uhrzeit sofern innerhalb eines Tages aufsteigend,
    was vermutlich am ehesten Deiner Absicht entspricht (und auch bei Access funktioniert)

    Die zweite Variante ermittelt die kleinste bzw. größte ID je Datum.
    Was etwas näher am Verhalten von Access dran liegt, unter der Voraussetzung an den IDs wurde niemals rumgedreht
    Was wiederum bei Access einfacher möglich wäre, als beim SQL Server (dort benötigt man IDENTITY_INSERT).
    Füge mal einen Datensatz mit einer ID zwischen bestehende ein, der wird dann letzter ;-)

    Gruß Elmar

    • Als Antwort markiert novus77 Dienstag, 21. Dezember 2010 20:05
    Montag, 20. Dezember 2010 22:44
    Beantworter

Alle Antworten

  • Hallo,

    Access FIRST und LAST sind nicht wirklich relational, da eine SQL-Abfrage (ohne ORDER BY) keine definierte
    Ordnung hat, kann es auch keine erste oder letzte Zeile geben. Da eine Access MDB auf einem ISAM basiert,
    funktioniert das dort (wenn auch mit einigen Annahmen).

    Im allgmeinen kann man aber FIRST durch MIN und LAST durch MAX ersetzen,
    die Bestandteil von ANSI-SQL sind und auch Access kennt sie im übrigen.

    Eine erweiterte Möglichkeite (ab SQL Server 2005, nicht Access) wären die Fenster-Funktionen,
    die man in Verbindung mit den Aggregatfunktionen kombinieren kann, siehe OVER-Klausel

    Konkrete Beispiele kann ich nachliefern, wenn Du einige Beispieldaten und einige exemplarische
    Auswertungen (ggf. das Access SQL) zeigst.

    Gruß Elmar

    Montag, 20. Dezember 2010 16:59
    Beantworter
  • Guten Abend Elmar,

     

    vielen Dank für die schnelle Hilfe.

    Hier mal ein paar Beispieldaten:

    CREATE TABLE [dbo].[meineTabelle]
    (
    	[ID] [int] IDENTITY(1,1) NOT NULL,
    	[Datum] [date] NULL,
    	[Uhrzeit] [time](0) NULL,
    	[Messwert] [float] NULL,
    ) 
    ON [PRIMARY]
    GO
    
    INSERT INTO [dbo].[meineTabelle] VALUES 
    	('12/16/2010' ,'08:01:00' ,23.25),
    	('12/16/2010' ,'09:12:00' ,23.00),
    	('12/16/2010' ,'16:44:00' ,23.63),
    	('12/17/2010' ,'07:15:00' ,23.79),
    	('12/17/2010' ,'10:32:00' ,23.55),
    	('12/17/2010' ,'19:51:00' ,23.63),
    	('12/18/2010' ,'08:20:00' ,23.50),
    	('12/18/2010' ,'13:21:00' ,23.49)
    GO
    
    

     

    Diese Beispieldaten konnte ich in MS Access wie folgt abfragen (Annahme: die Daten sind mittels ORDER BY Uhrzeit sortiert):

    SELECT [Datum]
        ,FIRST([Messwert]) as Erster
        ,MAX([Messwert]) as [Max]
        ,MIN([Messwert]) as [Min]
        ,LAST([Messwert]) as Letzter
    FROM [meineTabelle] 
    GROUP BY [Datum]
    

     

    Leider funktioniert das augenblicklich nicht mehr. Falls du mir wirklich ein paar Beispiele zeigen kannst, sage ich schon vorab vielen Dank.

     

    Viele Grüße

     

    Micha

    Montag, 20. Dezember 2010 20:18
  • Hallo Micha,

    in Deinem Fall wäre das in etwa:

    SELECT [Datum]
      ,(SELECT TOP (1) 
    		[Messwert]
    		FROM meineTabelle AS t2
    		WHERE t2.Datum = meineTabelle.Datum 
    		-- Uhrzeit aufsteigend sortiert
    		ORDER BY Uhrzeit) AS Erster
    	
      , MAX([Messwert]) as [Max]
      , MIN([Messwert]) as [Min]
      
      ,(SELECT TOP (1) 
    		[Messwert]
    		FROM meineTabelle AS t2
    		WHERE t2.Datum = meineTabelle.Datum 
    		-- Uhrzeit absteigend sortiert
    		ORDER BY Uhrzeit DESC) AS Letzter
    
    -- Alternativ via MIN/MAX(ID)
      ,(SELECT -- TOP (1) 
    		[Messwert]
    		FROM meineTabelle AS t2
    		WHERE t2.Datum = meineTabelle.Datum 
    			AND t2.ID = MIN([meineTabelle].ID)
    		) AS ErsterViaID
    
      ,(SELECT -- TOP (1) 
    		[Messwert]
    		FROM meineTabelle AS t2
    		WHERE t2.Datum = meineTabelle.Datum 
    			AND t2.ID = MAX([meineTabelle].ID)
    		) AS LetzterViaID
    
    FROM [meineTabelle] 
    GROUP BY [Datum]
    GO
    
    

    Wobei ich zwei Varianten eingebaut habe:
    Einmal über die Uhrzeit sofern innerhalb eines Tages aufsteigend,
    was vermutlich am ehesten Deiner Absicht entspricht (und auch bei Access funktioniert)

    Die zweite Variante ermittelt die kleinste bzw. größte ID je Datum.
    Was etwas näher am Verhalten von Access dran liegt, unter der Voraussetzung an den IDs wurde niemals rumgedreht
    Was wiederum bei Access einfacher möglich wäre, als beim SQL Server (dort benötigt man IDENTITY_INSERT).
    Füge mal einen Datensatz mit einer ID zwischen bestehende ein, der wird dann letzter ;-)

    Gruß Elmar

    • Als Antwort markiert novus77 Dienstag, 21. Dezember 2010 20:05
    Montag, 20. Dezember 2010 22:44
    Beantworter
  • Hallo Elmar,

     

    vielen Dank für die Beispiele. Leider kann ich sie mir erst heute Abend näher ansehen und ausprobieren. Ich werde mich später nochmals melden.

     

    Vielen Dank

     

    Gruß

    Micha

    Dienstag, 21. Dezember 2010 08:52
  • Hallo Elmar,

     

    vielen Dank für deine Hilfe. So habe ich es gemeint.

     

    Vielen Dank

     

    Micha

    Dienstag, 21. Dezember 2010 20:05