2010-05-28 12 views
5

Ich habe zwei Tabellen mit einer Spalte "Datum". Einer hält (Name, Datum) und der andere hält (Datum, p1, p2). Bei einem gegebenen Namen möchte ich das Datum in Tabelle 1 verwenden, um p1 und p2 aus Tabelle 2 abzufragen. Die Übereinstimmung sollte auftreten, wenn das Datum in Tabelle 1 innerhalb von zwei Sekunden nach Datum in Tabelle zwei liegt.Filter Objekte innerhalb von zwei Sekunden voneinander mit SQLAlchemy

Wie können Sie dies mit SQLAlchemy erreichen?

Ich habe versucht (erfolglos) den between Operator zu verwenden und mit einer Klausel wie:

td = datetime.timedelta(seconds=2) 
q = session.query(table1, table2).filter(table1.name=='my_name').\ 
    filter(between(table1.date, table2.date - td, table2.date + td)) 

Irgendwelche Gedanken?

Edit: Ich habe es geschafft, das Problem mit dem folgenden Ansatz zu lösen:

from sqlalchemy.sql import between 
import datetime 
# [all other relevant imports] 

td = datetime.timedelta(seconds=2) 
t1_entry = session.query(table_1).filter(table_1.name == 'the_name').first() 
if t1_entry is not None: 
tmin = t1_entry.date - td 
tmax = t1_entry.date + td 
t2_entry = session.query(table_2).filter(between(table_2.date, tmin, tmax)).first() 
return (t1_entry, t2_entry) 
return None 

So ist der Vergleich durchgeführt werden kann, aber ich bin nicht sicher, dass der Ansatz effizient ist.

Antwort

0

Nach einiger Zeit mit dieser Frage offen, der Ansatz ist, so weit das, was ich habe kommen mit:

from sqlalchemy.sql import between 
import datetime 
# [all other relevant imports] 

td = datetime.timedelta(seconds=2) 
t1_entry = session.query(table_1).filter(table_1.name == 'the_name').first() 
if t1_entry is not None: 
tmin = t1_entry.date - td 
tmax = t1_entry.date + td 
t2_entry = session.query(table_2).filter(between(table_2.date, tmin, tmax)).first() 
return (t1_entry, t2_entry) 
return None 

Wenn Sie eine bessere Idee haben, werde ich Ihre Antwort akzeptieren.

3

Lassen Sie mich zuerst erklären, warum das, was Sie versucht haben, nicht funktioniert. SQLAlchemy ist nur eine bequeme Möglichkeit, SQL-Abfragen zu schreiben, die Abfrage erfolgt dennoch auf der Remote-Seite. SQLAlchemy-Spalten sind spezielle Objekte, deren __eq__, usw. Methoden überschrieben werden, um nicht True oder False zurückzugeben, sondern andere spezielle Objekte, die sich daran erinnern, mit welchem ​​Objekt sie verglichen wurden und später entsprechende SQL-Anweisungen generieren können. Dasselbe gilt für das Hinzufügen von etc: Die benutzerdefinierte Methode __add__, __sub__ gibt keine Zahl oder eine verkettete Zeichenfolge zurück, sondern auch ein solches Objekt, das eine SQL-Anweisung generiert. Sie können sie zu Zeichenketten, Ganzzahlen usw., anderen Spalten, SELECT-Anweisungen, mysql-Funktionsaufrufen usw., , aber nicht zu speziellen Python-Objekten wie z. B. timedeltas vergleichen/hinzufügen. (vereinfachte, und wahrscheinlich technisch nicht 100% richtig;))

Also, was können Sie tun, ist:

  • die Werte in der Datenbank ganzen Zahlen Stellen, zB Unix-Zeitstempel. Auf diese Weise funktioniert Ihre between Abfrage (mit anstelle des Deltas)
  • Verwenden Sie Datenbank-Side-Funktionen, um das Datetime-Format-Datum in einen Unix-Zeitstempel zu konvertieren, und führen Sie dann den Vergleich.

UPDATE: Ich habe mit, dass rund ein wenig gespielt, und irgendwie es funktioniert, gibt es auch einen Interval Datentyp. Doch zumindest hier funktioniert es nicht richtig:

MySQL:

>>> db.session.execute(db.select([User.date_joined, User.date_joined + timedelta(seconds=2)], limit=1)).fetchall() 
[(datetime.datetime(2009, 7, 10, 20, 47, 33), 20090710204733.0)] 
>>> db.session.execute(db.select([User.date_joined, User.date_joined + 2], limit=1)).fetchall() 
[(datetime.datetime(2009, 7, 10, 20, 47, 33), 20090710204735.0)] 
>>> db.session.execute(db.select([User.date_joined+0, User.date_joined + 2], limit=1)).fetchall() 
[(20090710204733.0, 20090710204735.0)] 

SQLite:

>>> db.session.execute(db.select([User.date_joined, User.date_joined + timedelta(seconds=2)], limit=1)).fetchall() 
TypeError: expected string or buffer 
>>> db.session.execute(db.select([User.date_joined, User.date_joined + 2], limit=1)).fetchall() 
[(datetime.datetime(2010, 5, 28, 23, 8, 22, 476708), 2012)] 
>>> db.session.execute(db.select([User.date_joined+0, User.date_joined + 2], limit=1)).fetchall() 
[(2010, 2012)] 

Ich weiß nicht, warum die erste ausfällt auf MySQL und warum es schwimmt zurück. Die SQLite-Fehler scheinen zu geschehen, weil SQLite does not have a DATETIME data type and SQLAlchemy stores it as a string.

Sie müssen damit ein wenig herumspielen, vielleicht finden Sie einen Weg, der funktioniert - aber ich denke, um wirklich dbms unabhängig bleiben die Ganzzahl-Methode wird der einzig gangbare Weg sein.

+0

Diese Ausgabe eines anderen Formats für Zeitobjekte kann Kopfschmerzen bereiten! – Escualo

1

Der Ansatz besteht darin, die Daten in Unix-Zeitstempel zu konvertieren.

In einem kürzlich erschienenen Code benutzte ich die folgenden Zeilen erfolgreich:

from sqlalchemy.sql import func 
... 
q = q.join(q2, func.abs(func.unix_timestamp(rssi1.datetime)-func.unix_timestamp(q2.c.datetime)) <=2) 

Beachten Sie jedoch, dass func.xxx einfach Kopien xxx auf die Abfrage als String, so dass die Datenbank hat Funktion xxx zu unterstützen. Dieses Beispiel ist für MySQL.