を使用して、同様の何かを書くことができますSQLAlchemyので
は簡単な解決策が、最速ではないかもしれません。クイックで汚れた方法は、与えられた日時よりも大きく、より小さい和集合をフェッチし、昇順と降順にソートして1行目に限定してから、より小さい値のものを選択します。
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
とPython:12Sの分解能でタイムスタンプの年分とバックエンドとテストテーブルとしてPostgreSQLの使用例
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)
はでサブクエリをラップする、最も近い値をフェッチ組合を作成しますSELECTステートメントは、たとえば、SQLiteでも動作します。
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()
エイリアス組合
In [35]: testi_alias = aliased(Testi, the_union)
の結果にモデル所定の日時
In [36]: the_diff = testi_alias.key - the_time
又はフェッチ
In [36]: the_diff = func.julianday(testi_alias.key) - func.julianday(the_time)
のSQLiteでの差を算出近いです2のその奇妙さは、Postgresqlの間隔のうちgetting the absolute valueです。他のDBでは、差異計算と絶対値の取得には異なる解決策が必要です。 SQLiteは単にfunc.abs(the_diff)
です。単に差分により発注、制限の簡単な解決策は、このマシン上でいくつか800msで走っている間
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)
は、上記のクエリを約70-100msで終了します。データを2倍にすると、seqスキャンに依存する単純なソリューションも同様に倍増します。
組合がテーブルからこれらの2つの値を検索します:
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))]
そして最後に、あなたは一般的な機能でそれをすべてを包むことができます。
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)
select * from tableを使用していますか?datetime> your_date_time limit 1; select * from tableここで、datetime
Timo
私は行または時間の値を取得できますか? – Timo
2つの選択肢はソリューションの背後にあるアイデアですが、完全なソリューションではありません。最小の差が0であれば、特定のクエリは正しい結果を返しません。どちらのクエリも等価性が含まれていないためです。いずれかを返すようにクエリを適合させることができます。 –