[MYSQL] Mittelwert der letzten 24h

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
compy1
User
Beiträge: 2
Registriert: Freitag 30. März 2018, 10:11

Freitag 30. März 2018, 10:38

Hi,
ich versuche schon länger für ein Projekt Werte von der Datenbank abzufragen.
Ziel ist ein Mittelwert der letzten Stunde, Tag, Woche, Monat zu bekommen.
Leider funktioniert das nicht so ganz wie ich möchte.
Ich vermute es könnte am Timestamp liegen, allerdings fehlt hier mir etwas Grundwissen.
Jetzt bekomme ich bei allen Abfragen den Gleichen Wert ausgegeben.
Bin um jede Hilfe dankbar.

Hier ist mein Code:

Code: Alles auswählen

curs.execute("SELECT SUM(leistung) FROM erzeugung WHERE uhrzeit >= CURRENT_TIMESTAMP - INTERVAL 1 HOUR")
for leistung in curs.fetchall():
	print("Letzten 1h:")
	print("%.2f W" % leistung)

curs.execute("SELECT SUM(leistung) FROM erzeugung WHERE uhrzeit >= CURRENT_TIMESTAMP - INTERVAL 24 HOUR")
for leistung in curs.fetchall():
	print("Letzten 24h:")
	print("%.2f W" % leistung)

curs.execute ("SELECT SUM(leistung) FROM erzeugung WHERE uhrzeit >= CURRENT_TIMESTAMP - INTERVAL 7 DAY")
for leistung in curs.fetchall():
	print("Letzten 7d:")
	print("%.2f W" % leistung)
Datenbank:

Code: Alles auswählen

+----+------------+----------+------+--------+----------+
| id | datum      | uhrzeit  | volt | ampere | leistung |
+----+------------+----------+------+--------+----------+
|  1 | 2018-03-16 | 14:49:49 | 11.3 |      8 |     90.4 |
|  2 | 2018-03-16 | 14:53:08 | 11.3 |      8 |     90.4 |
|  3 | 2018-03-16 | 14:53:33 |   12 |      4 |       48 |
|  4 | 2018-03-16 | 14:53:56 |   12 |      4 |       48 |
|  5 | 2018-03-16 | 14:54:27 |   12 |      4 |       48 |
|  6 | 2018-03-16 | 14:54:30 |   12 |      4 |       48 |
|  7 | 2018-03-21 | 15:05:55 |   11 |      2 |       22 |
|  8 | 2018-03-21 | 15:10:20 |   11 |      2 |       22 |
|  9 | 2018-03-23 | 12:27:12 |   11 |      2 |       22 |
| 10 | 2018-03-23 | 12:27:49 |   11 |      2 |       22 |
| 11 | 2018-03-23 | 13:57:50 |   11 |      2 |       22 |
| 12 | 2018-03-23 | 14:02:25 |   11 |      2 |       22 |
| 13 | 2018-03-23 | 14:05:07 |   11 |      2 |       22 |
| 14 | 2018-03-23 | 14:05:14 |   11 |      2 |       22 |
| 15 | 2018-03-23 | 14:06:35 |   11 |      2 |       22 |
| 16 | 2018-03-23 | 14:07:07 |   11 |      2 |       22 |
| 17 | 2018-03-23 | 14:07:24 |   11 |      2 |       22 |
| 18 | 2018-03-23 | 14:07:47 |   11 |      2 |       22 |
| 19 | 2018-03-23 | 14:08:03 |   11 |      2 |       22 |
| 20 | 2018-03-23 | 14:08:25 |   11 |      2 |       22 |
| 21 | 2018-03-27 | 15:01:24 |   11 |      2 |       22 |
| 22 | 2018-03-27 | 15:02:20 |   11 |      2 |       22 |
| 23 | 2018-03-27 | 15:03:48 |   11 |      2 |       22 |
| 24 | 2018-03-30 | 11:07:19 |   11 |      2 |       22 |
+----+------------+----------+------+--------+----------+
Sirius3
User
Beiträge: 8427
Registriert: Sonntag 21. Oktober 2012, 17:20

Freitag 30. März 2018, 13:06

@compy1: Du hast in Deiner Tabelle zwei Felder datum und uhrzeit? Das sollte nicht sein. Mach daraus ein DATETIME-Feld. Bei einem SELECT das immer exakt ein Ergebnis liefert, nimmt man fetchone und keine for-Schleife.

EDIT: so wie es aussieht, hat MySQL große Probleme, Zeiten vernünftig zu speichern. Es kennt keine Zeitzonen bei Datentypen und nur eine Zeitzone für die gesamte Datenbank. Man kann also nur sinnvoll mit UTC arbeiten und das muß man sowohl beim Lesen als auch beim Schreiben berücksichtigen. Das Paket pytz bietet unter Python die dafür notwendige Unterstützung. Keine Ahnung, was die MySQL-Anbindung an Python datetime-Objekten mit Zeitzone macht. Müßte man wohl ausführlich testen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7472
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Sonntag 1. April 2018, 12:32

Für den Mittelwert bräuchte man auch die ``AVG()``-Funktion - nicht ``SUM()``!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3))
assert encoding_kapiert
compy1
User
Beiträge: 2
Registriert: Freitag 30. März 2018, 10:11

Samstag 14. April 2018, 12:04

Lieber spät als nie...
Ich bin zu einer Lösung gekommen.
Zuerst habe ich Uhrzeit und Datum als ein FELD zusammengefügt und als Timestamp formatiert.
Da ich meine DB Lokal betreibe sollte das mit der Uhrzeit kein Problem sein denke ich.
Somit funktioniert die Abfrage jetzt!
Und ja AVG() ist natürlich korrekt. SUM() hatte ich nur zu Testzwecken genutzt.
Danke für Eure Hilfe!

Code: Alles auswählen

curs.execute("SELECT AVG(leistung) FROM erzeugung WHERE date >= CURRENT_TIMESTAMP - INTERVAL 1 HOUR")
for leistung in curs.fetchone():
    global leistung_stunde
    leistung_stunde = leistung
    if leistung_stunde == None:
        leistung_stunde = 0

curs.execute("SELECT AVG(leistung) FROM erzeugung WHERE date >= CURRENT_TIMESTAMP - INTERVAL 24 HOUR")
for leistung in curs.fetchone():
    global leistung_tag
    leistung_tag = leistung
    if leistung_tag == None:
        leistung_tag = 0
    elif leistung_tag > 0:
        leistung_tag = leistung_tag/1000 # wegen Anzeige in kW

curs.execute ("SELECT AVG(leistung) FROM erzeugung WHERE date >= CURRENT_TIMESTAMP - INTERVAL 7 DAY")
for leistung in curs.fetchone():
    global leistung_woche
    leistung_woche = leistung/1000
    if leistung_woche == None:
        leistung_woche = 0
    elif leistung_woche > 0:
        leistung_woche = leistung_woche/1000

curs.execute ("SELECT AVG(leistung) FROM erzeugung WHERE date >= CURRENT_TIMESTAMP - INTERVAL 30 DAY")
for leistung in curs.fetchone():
    global leistung_monat
    leistung_monat = leistung/1000
    if leistung_monat == None:
        leistung_monat = 0
    elif leistung_monat > 0:
        leistung_monat = leistung_monat/1000
Sirius3
User
Beiträge: 8427
Registriert: Sonntag 21. Oktober 2012, 17:20

Samstag 14. April 2018, 14:32

@compy1: »global« nicht verwende, vor allem nicht so tief verschachtelt und auf Modulebene hat es sowieso keinen Effekt, weil dort alles global ist. Eine for-Schleife über ein Tupel mit exakt einem Element ist ziemlich sinnfrei. Die if-Abfragen sind auch überflüssig, da 0 / 1000 = 0 gilt.

Beleibt also:

Code: Alles auswählen

curs.execute ("SELECT AVG(leistung) FROM erzeugung WHERE date >= CURRENT_TIMESTAMP - INTERVAL 7 DAY")
leistung_woche = (curs.fetchone()[0] or 0) / 1000
Und um die vielen Codewiederholungen zu vermeiden, sollte man Parameter benutzen:

Code: Alles auswählen

STATISTICS = {
    "hour": 1, "day": 24, "week": 24*7, "month": 24*30
}

leistungen = {}
for name, hours in STATISTICS.items():
    curs.execute ("SELECT AVG(leistung) FROM erzeugung WHERE date >= CURRENT_TIMESTAMP - INTERVAL %s HOUR", [hours])
    leistungen[name] = (curs.fetchone()[0] or 0) / 1000
Antworten