Da der Primärschlüssel ist ein einfaches „Sortieren nach diff aufsteigend, holen 1. Reihe“ ist vielleicht nicht die schnellste sein, obwohl einfache Lösung. Eine schnelle und schmutzige Art und Weise könnte eine Vereinigung von größer als und kleiner als die gegebene Datetime, sortiert auf- und absteigenden und beschränkt sich auf der 1. Reihe, zu holen und dann mit dem kleineren diff vom 2.
auf einen Blick Hier ein Beispiel unter Verwendung von Postgresql als Backend und eine Testtabelle mit einem Jahr im wert von Zeitstempel mit 12s Auflösung:
sopython=> create table testi (key timestamp without time zone primary key);
CREATE TABLE
sopython=> insert into testi
select *
from generate_series(now() at time zone 'utc' - '1 year'::interval,
now() at time zone 'utc',
'12 seconds'::interval);
INSERT 0 2628001
und dem Python:
In [29]: from sqlalchemy import union_all, case
In [30]: from sqlalchemy.orm import aliased
In [31]: the_time = datetime(2016, 5, 5, 10, 45, 55)
die Vereinigung erstellen, die am nächsten wert abruft, Umwickeln die Unterabfragen in eine SELECT-Anweisung, so dass es funktioniert auch in SQLite zum Beispiel.
In [32]: greater = session.query(Testi).filter(Testi.key > the_time).\
...: order_by(Testi.key.asc()).limit(1).subquery().select()
In [33]: lesser = session.query(Testi).filter(Testi.key <= the_time).\
...: order_by(Testi.key.desc()).limit(1).subquery().select()
In [34]: the_union = union_all(lesser, greater).alias()
Alias das Modell auf dem Ergebnis der Vereinigung
In [35]: testi_alias = aliased(Testi, the_union)
Berechnen der Differenz aus dem vorgegebenen Datumzeit
In [36]: the_diff = testi_alias.key - the_time
oder in SQLite
In [36]: the_diff = func.julianday(testi_alias.key) - func.julianday(the_time)
Fetch je näher der 2. Die ca Se Monstrosität ist für getting the absolute value des Intervalls, in Postgresql. Andere DBs erfordern unterschiedliche Lösungen für die Differenzberechnung und den Absolutwert. Mit SQLite einfach func.abs(the_diff)
.
In [37]: session.query(testi_alias).\
...: order_by(case([(the_diff < timedelta(0), -the_diff)],
...: else_=the_diff)).\
...: first()
Out[37]: <sqlalchemy.ext.automap.testi at 0x7f096f837828>
In [38]: _.key
Out[38]: datetime.datetime(2016, 5, 5, 10, 45, 54, 855799)
Während die einfache Lösung nur durch diff Bestellung und in einigen 800ms auf dieser Maschine lief zu begrenzen, beendet die obige Abfrage in etwa 70-100ms. Wenn Sie die Daten verdoppeln, verdoppelt sich auch die einfache Lösung, die auf Seq-Scan basiert.
Die Vereinigung findet diese beiden Werte aus der Tabelle:
In [14]: session.query(testi_alias.key).all()
Out[14]:
[(datetime.datetime(2016, 5, 5, 10, 45, 54, 855799)),
(datetime.datetime(2016, 5, 5, 10, 46, 6, 855799))]
Und schließlich können Sie es wickeln alle in einer generischen Funktion auf:
def get_closest(session, cls, col, the_time):
greater = session.query(cls).filter(col > the_time).\
order_by(col.asc()).limit(1).subquery().select()
lesser = session.query(cls).filter(col <= the_time).\
order_by(col.desc()).limit(1).subquery().select()
the_union = union_all(lesser, greater).alias()
the_alias = aliased(cls, the_union)
the_diff = getattr(the_alias, col.name) - the_time
abs_diff = case([(the_diff < timedelta(0), -the_diff)],
else_=the_diff)
return session.query(the_alias).\
order_by(abs_diff.asc()).\
first()
get_closest(session, Testi, Testi.key, the_time)
Ist die Verwendung von Select * aus der Tabelle, wo datetime> your_date_time limit 1; Wählen Sie * aus der Tabelle where datetime
Timo
würde ich die Zeile oder den Zeitwert bekommen? – Timo
Die 2 Auswahlen sind die Idee hinter der Lösung, aber nicht die komplette Lösung. Beachten Sie, dass die bestimmten Abfragen das korrekte Ergebnis nicht zurückgeben, wenn die kleinste Differenz 0 ist, da keine der beiden Abfragen die Gleichheit enthält. Sie können die Abfrage so anpassen, dass sie entweder eins zurückgibt. –