angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

SQLAlchemy serverseitige datetime Berechnungen

Warum Sie versuchen sollten, client-seitige datetime Berechnungen zu vermeiden, wenn Sie SQLAlchemy nicht....

24 Juni 2019
post main image
Original photo unsplash.com/@nputra.

Hier finden Sie viele SQLAlchemy datetime Berechnungsbeispiele, z.B. mit der timedelta Funktion 's. Warum? Ich verstehe das nicht, außer dass das einfach ist. Aber ist es richtig?

Angenommen, wir wollen alle Benutzerdatensätze oder Objekte, die vor zwei Stunden erstellt wurden und die Datensatz / Objektdefinition ist:

class User(Base):

    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    created_on = Column(DateTime, server_default=func.now(), index=True)
    email = Column(String(100), server_default='', index=True)

Wenn Python wir dann die Datensätze / Objekte auswählen könnten, die in den letzten 10 Minuten hinzugefügt wurden, könnten wir so etwas wie Folgendes tun:

from datetime import datetime, timedelta

now = datetime.now()
two_hours_ago = now - timedelta(hours=2)

# return all users created less then 2 hours ago
db.query(User).filter(User.created_on > two_hours_ago).all()

Die generierte SQL ist:

SELECT user.id AS user_id, user.created_on AS user_created_on, user.email AS user_email
FROM user 
WHERE user.created_on > %(created_on_1)s
INFO sqlalchemy.engine.base.Engine {'created_on_1': datetime.datetime(2019, 6, 25, 7, 31, 58, 630959)}

Dies funktioniert nur, gibt valide Ergebnisse, wenn:

  • der Datenbankserver läuft auf dem gleichen Server, auf dem auch der Python Code läuft.
  • der Datenbankserver auf einem anderen Server als der Python Code-Server läuft und die Zeit auf beiden Servern perfekt synchronisiert ist.

Angenommen, Sie haben einen separaten Datenbankserver und die Zeit dieses Servers ist 2 Minuten außerhalb der Synchronisation. Dann erhalten Sie falsche, unvollständige Ergebnisse. Ich schreibe seit vielen Jahren serverseitige Anfragen und bin überrascht, dass es in SQLAlchemy Fragen und Antworten wenig Aufmerksamkeit dafür gibt.

Der einzige Weg, um die richtigen Ergebnisse zu erzielen, besteht darin, die datetime Stempel der Datensätze des Datenbankservers zu verwenden und sie zu addieren datetime oder davon abzuziehen datetime . Mit MariaDB / MySQL können Sie die Intervallanweisung verwenden:

SELECT user.* FROM user WHERE created_on > (NOW() - INTERVAL 2 HOUR)

Leider konnte ich keine Lösung finden, SQLAlchemy die für alle Datenbanken gültig wäre. SQLAlchemy Hat das text() Objekt, übergibt es den Wert an die Abfrage. Mit text()wird die SQLAlchemy Abfrage zu:

from sqlalchemy import text

two_hours_ago = text('NOW() - INTERVAL 2 HOURS')

# return all users created less then 2 hours ago
db.query(User).filter(User.created_on > two_hours_ago).all()

Die generierte SQL ist:

SELECT user.id AS user_id, user.created_on AS user_created_on, user.email AS user_email
FROM user 
WHERE user.created_on > NOW() - INTERVAL 2 HOUR

Beachten Sie, dass diese Abfrage möglicherweise nicht auf allen Datenbanksystemen funktioniert. Es funktioniert mit MariaDB / MySQL aber es funktioniert sicherlich nicht mit SQLite.

Wenn Sie eine Anwendung entwickeln und alles auf einem Computer laufen lassen, dann denken Sie immer daran, dass Sie die Datenbank in Zukunft vielleicht auf einem separaten Server betreiben möchten. Es ist also keine schlechte Idee, Ihre Anfragen für diese Situation zu entwickeln.

Links / Impressum

Flask-sqlalchemy query datetime intervals
https://stackoverflow.com/questions/30495935/flask-sqlalchemy-query-datetime-intervals

SQLAlchemy datetime operations on server side
https://stackoverflow.com/questions/12540175/sqlalchemy-datetime-operations-on-server-side

SQLAlchemy default DateTime
https://stackoverflow.com/questions/13370317/sqlalchemy-default-datetime

Using DATEADD in sqlalchemy
https://stackoverflow.com/questions/15572292/using-dateadd-in-sqlalchemy/15573750#15573750

Mehr erfahren

SQLAlchemy

Einen Kommentar hinterlassen

Kommentieren Sie anonym oder melden Sie sich zum Kommentieren an.

Kommentare (5)

Eine Antwort hinterlassen

Antworten Sie anonym oder melden Sie sich an, um zu antworten.

avatar

Another great post. I have to agree it is surprising most solutions on the web ignore the potential Python app versus DBMS clock difference problem. The kind of bug that waits patiently until its time!
FWIW `sqlalchemy.sql.expression.func.now() - timedelta(minutes=2)` seems to work for Postgres and I would expect others with a NOW() function.

avatar
Anonymer Besucher (nicht eingeloggt) 3 Jahre vor Anonymer Besucher (nicht eingeloggt)

I just noticed the post above immediately displayed as posted 1 hour ago . . . I'm on GMT (London).

avatar
Anonymer Besucher (nicht eingeloggt) 3 Jahre vor Anonymer Besucher (nicht eingeloggt)

Me again! But after posting the second post, the first changed to "2 minutes ago", the second started at "0 seconds ago"!

avatar
Anonymer Besucher (nicht eingeloggt) 3 Jahre vor Anonymer Besucher (nicht eingeloggt)

Then after the third post all three now say "1 hour" . . . had to wait 5 minutes to post this one :-)

avatar
peter 3 Jahre vor Anonymer Besucher (nicht eingeloggt)

Thank you for reporting this. I am still working on many parts of this website ... will fix this soon.