Verbrauchsberechnung - Summierung/Mittelwert über mehrere DAtensätze abhängig vom Inhalt eines Hatensatzes

mareinki

Fleissiger Benutzer
Beiträge
60
Hallo!

Ich verwalte die Aufladungen meines Elektroatauto in einer einfachen Tabelle T_ Elektroauto (Datum, Ladung, Vollladung ja/nein, km_Stand).
Da ich selten Volllade sondern abhängig davon wieviel meine PV-Anlage produziert gibt es mehrere Datensätze mit Vollladung=nein und dann immer wieder mal Datensätze mit Volladung=ja.
Ich habe nun einen Abfrage gemacht in der ich jeweils die Differenz zwischen den Datensätze berechne, also zB di gefahrenen km zwischen den Ladungen.
Ich möchte nun jeweils den Verbrauch aber natürlich nur zwischen den Volladungen ermitteln, wenn geht mit SQL-Abfrage, bzw mit VBA Script.
D.h. es ist notwendig die Summe der Ladungen zwischen zwei Vollladungen und die gefahrenen km zwischen den Vollladungen zu ermitteln.
Aber wie ich das machen könnte, ist mir noch unklar. Hat jemand einen Idee dazu?

Anbie meine Test-Datenbank dazu

Grüße
Markus
 

Anhänge

Werbung:
Hallo Markus,
der Ansatz wäre, mit HIlfe von VBA eine Durchschnittstabelle zu erstellen, weil einmal summiert (KW) und einmal Differenzen (Start/Ende-Km) gebildet werden müssen. Ich habe das mal versucht, aber dabei kommen mir deine Testdaten etwas komisch vor. Die Buchungen 11 und 12 erscheinen mir nicht plausibel, weil für wesentlich weniger Km ein mehr als doppelt so hoher Verbrach gebucht wurde. Bitte prüfe das nochmal, bevor ich hier eine Lösung zeige.
 
Hallo Andreas!

Die Daten stimmen schon, denn
Pos 12 (9.5,2026) wurde vollgeladen, km vom letzten Volladen (4761-4696)=65 km, geladen wurden 9,68 kWh --> Verbrauch 14,0 kWh/100km
Pos 11 (3.5.2026) wurde vollgeladen (letzte Volladung war Pos7), daher (4696-4161)=535 km, geladen wurden insgesamt 85,94 kWh --> 16,1 kWh/100km

Grüße
Markus
 
Definiere eine Arbeitstabelle
1779036495447.webp
1779037053731.webp

Kopiere folgenden Code in ein neues, allgemeines Modul, z.B. modDurchschnitte:
Es wird die komplette Tabelle T-Elektroauto abgearbeitet und die Tabelle T_Durchschnitte wird jedesmal
geleert und dann wieder aktuell befüllt. So können bei Buchungsfehlern einzelne Sätze in der Ausgangstabelle korrigiert und die Durchschnitte immer wieder neu berechnet werden.
Die Ausgangstabelle muss, so wie es im Test war, nach Datum aufsteigend sortiert sein.

Code:
Option Compare Database
Option Explicit

Dim db As Database
Dim rs As Recordset
Dim rsd As Recordset

Dim KW_Summe As Double
Dim Km_Diff As Double
Dim Km_Start As Double
Dim Datum_von As Date
Dim Datum_bis As Date

Dim sqlstr As String
Sub erzeugen_Durchschnittstabelle()

Set db = CurrentDb
Set rs = db.OpenRecordset("T_Elektroauto")
Set rsd = db.OpenRecordset("T_Durchschnitte")

sqlstr = "DELETE * FROM T_Durchschnitte;"
db.Execute sqlstr

rs.MoveFirst
KW_Summe = 0 'Startwert
Km_Diff = 0
Km_Start = rs!km_Stand
Datum_von = rs!Datum
Datum_bis = rs!Datum

Do Until rs.EOF
      
   KW_Summe = KW_Summe + rs!Ladung
   Datum_bis = rs!Datum
  
   If rs!Volladung = True Then
       Km_Diff = rs!km_Stand - Km_Start
      
       Durchschnitt_schreiben
      
       KW_Summe = 0
       Km_Diff = 0
      
       Km_Start = rs!km_Stand
       Datum_von = rs!Datum
   End If
  
   rs.MoveNext
Loop


Set db = Nothing
Set rs = Nothing
Set rsd = Nothing

End Sub
Sub Durchschnitt_schreiben()
    
    With rsd
     .AddNew
     !Datum_von = Datum_von
     !Datum_bis = Datum_bis
     !Gesamt_Ladung = KW_Summe
     !Gesamt_Km = Km_Diff
     If Km_Diff > 0 Then
        !Durchschnitt_KW_pro_100km = KW_Summe / Km_Diff * 100
     End If
     .Update
    End With
End Sub

Bei Fragen gerne melden.
 
Ich kann leider kein Access öffnen und sehe daher die Datensätze nicht. Es müsste doch jeder Ladevorgang, unabhängig ob Vollladung oder nicht, relevant sein, oder nicht? Wenn ich mein Auto nur halb lade, und erst beim nächsten mal voll, dann verbrauche ich doch dennoch Strom aus beiden Ladevorgängen.

Leider ist Access so semi geil für den Job, da keine Window-Funktionen verfügbar.
 
Da Ladevorgänge und und Fahrtstrecken asynchron sind, geht die Durchnittsberechnung nur zum gemeinsamen Zeitpunkt der Datenerfassung, nämlich der Vollladung und den dann entstandenen Summen, bzw. Differenzen. So ist es in dem Modul realisiert. Da es in VBA realisiert ist, hat es wieder mal nix mit dem vermeintlich "uncoolen" Access zu tun, sondern ist eine reine Frage der Logik.
Für solche (kleinen) Aufgaben ist Access geradzu prädestiniert.
 
Da Ladevorgänge und und Fahrtstrecken asynchron sind, geht die Durchnittsberechnung nur zum gemeinsamen Zeitpunkt der Datenerfassung, nämlich der Vollladung und den dann entstandenen Summen, bzw. Differenzen.
Darauf bezieht sich ja meine Frage. Ist es wirklich so dass nur, wenn Vollladung = True, auch geladen wurde oder wird auch geladen, wenn es sich nicht um eine "Vollladung" handelt? Meine Annahme wäre, das ein Datensatz auch immer Ladung bedeutet, wenn auch nicht auf 100%. Wenn ich aber nicht volltanke, tanke ich ja dennoch.
Für solche (kleinen) Aufgaben ist Access geradzu prädestiniert.
Man kann das zweifelsohne in Access mit VBA machen. Aber auch SQL kann sowas leisten bzw. ist prädestiniert, weil effizient. Window-Funktionen vorausgesetzt.
 
Leider ist Access so semi geil für den Job, da keine Window-Funktionen verfügbar.
Die Lösung in Access steht oben. Ob man das "geil" findet oder nicht ist in dem Zusammenhang unerheblich. Es funktioniert.
Darauf bezieht sich ja meine Frage. Ist es wirklich so dass nur, wenn Vollladung = True, auch geladen wurde oder wird auch geladen, wenn es sich nicht um eine "Vollladung" handelt? Meine Annahme wäre, das ein Datensatz auch immer Ladung bedeutet, wenn auch nicht auf 100%. Wenn ich aber nicht volltanke, tanke ich ja dennoch.
Tankmengen addieren von Vollladung bis nächster Vollladung. Ebenso die Differenz der Km zwischen den beiden Volladungen und dann den Durchschnitt/100 km berechnen. Eigentlich ganz simpel.
Man kann das zweifelsohne in Access mit VBA machen. Aber auch SQL kann sowas leisten bzw. ist prädestiniert, weil effizient. Window-Funktionen vorausgesetzt.
Es wäre schön, eine Lösung in SQL zu sehen. Möglichst mit der Erklärung, wie ich es so einfach wie in Access in ein Frontend einbinden kann.
Hier dazu die Ausgangstesttabelle von Markus, da Access bei @ukulele ja nicht zur Verfügung steht.
Zwi.webp
 
Es wäre schön, eine Lösung in SQL zu sehen. Möglichst mit der Erklärung, wie ich es so einfach wie in Access in ein Frontend einbinden kann.
Hier dazu die Ausgangstesttabelle von Markus, da Access bei @ukulele ja nicht zur Verfügung steht.
Anhang anzeigen 2643
SQL mit Window-Funktionen (also nicht in Access anwendbar aber als Referenz)
Code:
WITH T_Elektroauto(ID,Datum,Ladung,Volladung,km_Stand) AS (
    SELECT 1,cast('2026-03-02' AS DATE),24.5,cast(1 AS BIT),3285 UNION ALL
    SELECT 2,'2026-03-10',4.5    ,0,3335 UNION ALL
    SELECT 3,'2026-03-31',40.5    ,0,3935 UNION ALL
    SELECT 4,'2026-04-01',16.25    ,0,3985 UNION ALL
    SELECT 5,'2026-04-05',14    ,0,4010 UNION ALL
    SELECT 6,'2026-04-06',5.3    ,0,4070 UNION ALL
    SELECT 7,'2026-04-17',41.4    ,1,4161 UNION ALL
    SELECT 8,'2026-04-24',17.85    ,0,4200 UNION ALL
    SELECT 9,'2026-04-26',21.95    ,0,4400 UNION ALL
    SELECT 10,'2026-04-30',21.14,0,4670 UNION ALL
    SELECT 11,'2026-05-03',25    ,1,4696 UNION ALL
    SELECT 12,'2026-05-09',9.68    ,1,4761
    ), t1 AS (
    SELECT    *,
            km_Stand - lag(km_Stand) OVER (ORDER BY ID ASC) AS gefahrene_km,
            lag(Volladung) OVER (ORDER BY ID ASC) AS zuvor_Vollladung
    FROM    T_Elektroauto
    ), t2 AS (
    SELECT    *,
            isnull(sum(zuvor_Vollladung) OVER (ORDER BY ID ASC),0) AS ID_Vollladezyklus
    FROM    t1
    ), t3 AS (
    SELECT    *,
            sum(Ladung) OVER (PARTITION BY ID_Vollladezyklus ORDER BY ID) AS sum_Ladung,
            sum(gefahrene_km) OVER (PARTITION BY ID_Vollladezyklus ORDER BY ID) AS sum_gefahrene_km
    FROM    t2
    )
SELECT    ID,
        Datum,
        km_Stand,
        ID_Vollladezyklus,
        sum_Ladung,
        sum_gefahrene_km,
        sum_gefahrene_km / sum_Ladung AS Verbrauch
FROM    t3
WHERE    Volladung = 1
ORDER BY ID ASC;
Ist ein wenig wild weil viele verschachtelte Selects - eventuell noch optimierungsfähig. Man könnte hier auch Gruppieren, etc., es geht mir nur um ein Beispiel und Verprobung.

SQL (sehr warscheinlich Access tauglich)
Code:
WITH T_Elektroauto(ID,Datum,Ladung,Volladung,km_Stand) AS (
    SELECT 1,cast('2026-03-02' AS DATE),24.5,cast(1 AS BIT),3285 UNION ALL
    SELECT 2,'2026-03-10',4.5    ,0,3335 UNION ALL
    SELECT 3,'2026-03-31',40.5    ,0,3935 UNION ALL
    SELECT 4,'2026-04-01',16.25    ,0,3985 UNION ALL
    SELECT 5,'2026-04-05',14    ,0,4010 UNION ALL
    SELECT 6,'2026-04-06',5.3    ,0,4070 UNION ALL
    SELECT 7,'2026-04-17',41.4    ,1,4161 UNION ALL
    SELECT 8,'2026-04-24',17.85    ,0,4200 UNION ALL
    SELECT 9,'2026-04-26',21.95    ,0,4400 UNION ALL
    SELECT 10,'2026-04-30',21.14,0,4670 UNION ALL
    SELECT 11,'2026-05-03',25    ,1,4696 UNION ALL
    SELECT 12,'2026-05-09',9.68    ,1,4761
    )
SELECT    max(ID) AS ID,
        max(Datum) AS Datum,
        max(km_Stand) AS km_Stand,
        ID_Vollladezyklus,
        sum(Ladung) AS sum_Ladung,
        sum(gefahrene_km) AS sum_gefahrene_km,
        sum(gefahrene_km) / sum(Ladung) AS Verbrauch
FROM    (

SELECT    t1.*,
        t1.km_Stand - t0.km_Stand AS gefahrene_km,
        isnull((    SELECT    sum(Volladung)
                    FROM    T_Elektroauto
                    WHERE    T_Elektroauto.ID < t1.ID ),0) AS ID_Vollladezyklus
FROM    T_Elektroauto t1
LEFT JOIN T_Elektroauto t0
ON        t1.ID - 1 = t0.ID

        ) t2

GROUP BY ID_Vollladezyklus
ORDER BY max(ID) ASC;
Ist erstmal gar nicht wild. So ein Subselect kann natürlich nasty werden bei sehr vielen Datensätzen. Der ganze Teil mit WITH kann weg, wenn man die Tabelle T_Elektroauto schon hat.

Ergebnis ist bei mir in beiden Varianten deckungsgleich:
IDDatumkm_StandID_Vollladezyklussum_Ladungsum_gefahrene_kmVerbrauch
12026-03-023285024.50NULLNULL
72026-04-1741611121.958767.18327183271832718327183271
112026-05-034696285.945356.22527344659064463579241331
122026-05-09476139.68656.71487603305785123966942148
 
Werbung:
Na, bis auf die Durchschnittsberechnung
Code:
sum(gefahrene_km) / sum(Ladung) AS Verbrauch
, sieht das ja schon ganz gut aus.

Code:
sum(Ladung) /sum(gefahrene_km) * 100 as Verbrauch
wäre, glaube ich, besser. Wobei die Division durch Null noch abgefangen werden müsste.
 
Zurück
Oben