Seite 1 von 1

Vergleich von Daten (Datum)

Verfasst: Donnerstag 15. August 2019, 11:56
von NewPython19
Hallo zusammen,

ich habe eine Datenbank (SQLite) mit einer Tabelle und mehreren Datenfeldern.
Eines dieser Datenfelder heißt "Date" und beinhaltet wie der Name schon, ein Datum.

Mit Hilfe einer Funktion möchte ich bestimmte Datensätze löschen, wenn das Datum eine bestimmte Anzahl Tage zurückliegt.

Hier meine Funktion:

Code: Alles auswählen

def delete_data(connection, cursor):
    cursor.execute("SELECT * FROM Table")
    for dataset in cursor:
        datasetDate = dataset[0]
        today = datetime.datetime.now()
        timeDelta = datetime.timedelta(days=30)
        dateDifference = today - timeDelta
        deltaDate = dateDifference.strftime("%d.%m.%Y")
        if datasetDate < deltaDate:
            cursor.execute("DELETE FROM Table WHERE Date = (?)", (datasetDate,))
            connection.commit()
Beim Testen dieser Funktion werden irgendwie alle Datensätze gelöscht. Weiß jemand wo mein Fehler liegt? Ich hab schon ein bisschen rumgespielt aber irgendwie komme ich auf keine Lösung :shock:

Re: Vergleich von Daten (Datum)

Verfasst: Donnerstag 15. August 2019, 12:08
von __deets__
Du musst nur EINMAL das Verfallsdatum berechnen. Also quasi „threshold = now() - timedelta()“.

Und dann die sql Datenbank die Arbeit machen lassen.

DELETE FROM Tabelle WHERE date < ?

Re: Vergleich von Daten (Datum)

Verfasst: Donnerstag 15. August 2019, 12:15
von sparrow
Wobei man im Hinterkopf haben sollte, dass sqlite keinen Datentyp für Datum und/oder Uhrzeit hat. Und wenn man tag.monat.Jahr in die Datenbank schreibt, lässt sich das ganz schlecht sortieren / vergleichen, weil der 15.01.2019 möglicherweise vor dem 22.09.2018 einsortiert wird.

Re: Vergleich von Daten (Datum)

Verfasst: Donnerstag 15. August 2019, 12:21
von __deets__
Also laut deinem link benutzen die iso-Format, und da ist dir lexikalische auch die logische Ordnung.

Re: Vergleich von Daten (Datum)

Verfasst: Donnerstag 15. August 2019, 12:34
von sparrow
Das ist richtig.
Allerdings macht der TE Dinge mit .strftime() - und wenn er das so wie gezeigt auch tut, wenn er Daten in die Datenbank schreibt, hat er ein Problem.

Re: Vergleich von Daten (Datum)

Verfasst: Donnerstag 15. August 2019, 12:35
von __blackjack__
Die Frage ist halt wie der OP das in die DB geschrieben hat. Im Beispiel vewendet er ja tag.monat.jahr als Format.

Ich würde ja wie immer an dieser Stelle zu SQLAlchemy raten. Das konvertiert als DATE angegebene Spalten transparent von/nach `datetime.date` – auch bei SQLite.

Re: Vergleich von Daten (Datum)

Verfasst: Donnerstag 15. August 2019, 12:35
von NewPython19
Ach Herrje! Stimmt, es reicht aus das Datum nur einmal berechnen zu lassen! Vielen Dank!

Code: Alles auswählen

def delete_data(connection, cursor):
    cursor.execute("SELECT * FROM Table")
    today = datetime.datetime.now()
    timeDelta = datetime.timedelta(days=5)
    dateDifference = today - timeDelta
    deltaDate = dateDifference.strftime("%d.%m.%Y")
    cursor.execute("DELETE FROM Table WHERE Date < (?)", (deltaDate,))
    connection.commit()

Re: Vergleich von Daten (Datum)

Verfasst: Donnerstag 15. August 2019, 12:41
von sparrow
Warum selektierst du erst Sachen, wenn du es hinterher nicht verwendest?
Ich bleibe dabei: Ich bin mir ziemlich sicher, dass der Vergleich mit einem Tag.Monat.Jahr String, den du hier durchführst, falsch ist.

Code: Alles auswählen

> sqlite3.exe
SQLite version 3.29.0 2019-07-10 17:32:03
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> CREATE TABLE test (id INTEGER PRIMARY KEY, datum DATE);
sqlite> INSERT INTO test (id, datum) VALUES (1, '2019-01-15');
sqlite> SELECT * FROM test;
1|2019-01-15
sqlite> DELETE FROM test WHERE datum < '30.06.1986';
sqlite> SELECT * FROM test;
sqlite> INSERT INTO test (id, datum) VALUES (2, '15.01.2019');
sqlite> SELECT * FROM test;
2|15.01.2019
sqlite> DELETE FROM test WHERE datum < '22.12.1968';
sqlite> SELECT * FROM test;
sqlite>

Re: Vergleich von Daten (Datum)

Verfasst: Donnerstag 15. August 2019, 13:04
von __blackjack__
@NewPython19: Namen werden in Python klein_mit_unterstrichen geschrieben – auch lokale Namen. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase). Beides kommt eher selten bis nie lokal vor.

Cursor sind eher etwas kurzlebiges, den würde ich nicht als Argument herum reichen solange sich die Aufrufe nicht auf die selbe Transaktion beziehen – was hier hoffentlich nicht der Fall ist, denn das wäre etwas was man *deutlich* dokumentieren sollte.

Man muss auch nicht wirklich *jedes* Zwischenergebnis von noch so kleinen Trippelschrittchen an einen eigenen Namen binden.

Ich würde in den Funktionsnamen eine Hinweis aufnehmen was da gelöscht wird.

Ungetestet:

Code: Alles auswählen

def delete_old_data(connection, days_back=5):
    timestamp = datetime.datetime.now() - datetime.timedelta(days=days_back)
    connection.cursor().execute(
        "DELETE FROM table WHERE date < ?", (timestamp.date(),)
    )
    connection.commit()

Re: Vergleich von Daten (Datum)

Verfasst: Donnerstag 15. August 2019, 13:42
von NewPython19
Ich hab eure Kommentare und Rückmeldungen noch mit umgesetzt und letzte Fehler ausgebessert:

Code: Alles auswählen

def delete_data(connection):
    today = datetime.datetime.now()
    time_delta = datetime.timedelta(days=30)
    date_difference = today - time_delta
    connection.cursor().execute("DELETE FROM Table WHERE Date = (?)", (date_difference.date(),))
    connection.commit()

Re: Vergleich von Daten (Datum)

Verfasst: Donnerstag 15. August 2019, 13:47
von sparrow
sqlite3.PARCE_DECLTYPES und sqlite3.PARSE-COLNAMES machen einem das Leben sehr viel leichter. Dann sorgt das sqlite3-Modul unter anderem dafür, dass datetime.date-Objekte korrekt geparst in der Datenbank landen und nach dem Select auch wieder datetime.date-Objekte sind.
Es muss nicht zwangsläufig gleich SQLAlchemy sein.

Code: Alles auswählen

import sqlite3
from datetime import date, timedelta


con = sqlite3.connect(":memory:",
                detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)


con.execute("CREATE TABLE test (id INTEGER PRIMARY KEY, datum DATE)")

today = date.today()
con.execute("INSERT INTO test (id, datum) VALUES (?, ?)", (1, today))
for entry in con.execute("SELECT id, datum FROM test"):
    print(type(entry[0]), type(entry[1]))
    # <class 'int'> <class 'datetime.date'>
tomorrow = today + timedelta(1)
con.execute("DELETE FROM test WHERE datum < ?", (tomorrow,))

Re: Vergleich von Daten (Datum)

Verfasst: Montag 19. August 2019, 07:37
von NewPython19
Guten Morgen,

mir ist nochmal ein Fehler aufgefallen glaube ich...
Ich habe in meiner Tabelle das Datum, bestehend aus Datum und Uhrzeit in zwei Datenfelder aufgeteilt...
Damit ist doch mein Datum in meinem Datenfeld Date ein String und kein Datumsobjekt mehr oder? Kann es sein, dass daher meine Datumsberechnung nicht 100% funktioniert?

Re: Vergleich von Daten (Datum)

Verfasst: Montag 19. August 2019, 08:02
von sparrow
Wie ich bereits schrieb: in Sqlite gibt es kein Datumsfeld. Das ist immer ein String.

Wenn du Datum und Zeit trennst, wird es mit Sortierungen, etc, wieder schwierig.

Mach es wie in meinem letzten Beispiel gezeigt. Gib der Spalte den Typ datetime und nimm direkt datetime-Objekt für alles. Das sqlite3-Modul kümmert sich um den Rest.

Re: Vergleich von Daten (Datum)

Verfasst: Montag 19. August 2019, 08:18
von snafu
Für das Speichern von Datumsangaben bietet sich isoformat() an, sofern das Datenformat keinen eigenen Typen dafür hat. Dann muss man sich keine großen Gedanken mehr um die Formatierung machen. Dieses Format ist geeignet zum Sortieren und wird auch von anderen Programmen leicht verstanden, wenn sie ein Datum verarbeiten können. Seit Python 3.7 gibt es mit fromisoformat() auch die passende Umkehrfunktion dazu.