2010-05-28 11 views
5

Mam dwie tabele z kolumną "data". Jeden zawiera (imię i nazwisko, data), a drugi trzyma (data, p1, p2). Biorąc pod uwagę nazwę, chcę użyć daty z tabeli 1 do zapytania p1 i p2 z tabeli drugiej; mecz powinien się odbyć, jeśli data w tabeli pierwszej jest w ciągu dwóch sekund od daty w tabeli drugiej.Filtrowanie obiektów w ciągu dwóch sekund względem siebie przy użyciu SQLAlchemy

Jak można to osiągnąć za pomocą SQLAlchemy?

próbowałem (bezskutecznie), aby użyć operatora between oraz z klauzulą ​​jak:

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)) 

jakieś przemyślenia?

Edit: udało mi się rozwiązać ten problem stosując następujące metody:

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 

Więc porównanie można zrobić, ale nie jestem pewien, że podejście jest skuteczne.

Odpowiedz

0

Po pewnym czasie z tym pytaniem otwartym, podejście do tej pory jest to jeden mam wymyślić:

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 

Jeśli masz lepszy pomysł, będę akceptować swoją odpowiedź.

3

Pozwól mi najpierw wyjaśnić, dlaczego to, co próbowałeś, nie działa. SQLAlchemy jest po prostu wygodnym sposobem pisania zapytań SQL, wszystkie zapytania są jednak wykonywane po stronie zdalnej. Kolumny SQLAlchemy są specjalnymi obiektami, których metody są nadpisywane, aby zwrócić nie inne obiekty specjalne, które pamiętają obiekt, z którym zostały porównane i mogą później wygenerować odpowiednie instrukcje SQL. To samo dotyczy dodawania itd .: Metoda niestandardowa nie zwraca liczby lub połączonego ciągu, ale także takiego obiektu, który generuje instrukcję sql. Możesz porównać/dodać je do łańcuchów, liczb całkowitych itp., Innych kolumn, instrukcji wyboru, wywołań funkcji mysql itp., , ale nie do specjalnych obiektów pythonowych, takich jak timedeltas. (uproszczony i prawdopodobnie nie technicznie w 100% poprawne;))

Więc co można zrobić, to:

  • Wprowadź wartości w całkowitych baz danych, np sygnatury czasowe unix. W ten sposób twoje zapytanie between zadziała (z 2 zamiast delta)
  • Użyj funkcji po stronie bazy danych, aby przekonwertować datę formatu datetime na uniksowy znacznik czasu, a następnie dokonać porównania.

UPDATE: Grałem około trochę z tym, i jakoś to nie praca, to nawet jest typem Interval danych. Jednak przynajmniej tutaj nie działa prawidłowo:

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)] 

Nie wiem, dlaczego nie pierwsza na MySQL i dlatego zwraca pływaków. Błędy SQLite wydają się występować, ponieważ SQLite does not have a DATETIME data type and SQLAlchemy stores it as a string.

Będziesz musiał trochę się z tym bawić, może znajdziesz sposób, który działa - ale myślę, że aby pozostać naprawdę niezależnym od DBMS, metoda liczby całkowitej będzie jedynym możliwym sposobem.

+0

To wydanie różnych formatów obiektów czasu może stać się bólem głowy! – Escualo

1

Podejście polega na konwersji dat na znaczniki czasu unix.

W ostatnim kodzie użyłem następujące linie powodzeniem:

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

jednak pamiętać, że func.xxx prostu kopiuje xxx do kwerendy jako ciąg znaków, więc baza danych musi obsługiwać funkcję xxx. Ten przykład dotyczy MySQL.

Powiązane problemy