web-dev-qa-db-ja.com

Sqlalchemyはリストのフィールドでフィルターしますが、元の順序を維持しますか?

私はこのような靴モデルを持っています:

_class Shoe(db.Model):
id = db.Column(db.Integer, primary_key = True)
asin = db.Column(db.String(20), index = True)
_

Ids = [2,1,3]のようなIDのリストがあり、Shoeモデルでクエリを実行して、結果が 'ids'リストにIDを持つようにすると、[{id:2、asin: "が必要です。 111 "}、{id:1、asin:" 113 "}、{id:3、asin:" 42 "}]しかし、問題は、次のクエリステートメントを使用すると元の順序が保持されず、結果が表示されることです。バックランダム。フィルタリングしたリストの順序を維持するにはどうすればよいですか?

正しくないもの:Shoe.query.filter(Shoe.id.in_(my_list_of_ids)).all()

13
user1835351

IDの妥当な小さなリストがある場合は、各IDに対して個別にSQLクエリを実行できます。

[Shoe.query.filter_by(id=id).one() for id in my_list_of_ids]

IDの数が多いと、SQLクエリに時間がかかります。次に、単一のクエリを使用し、2番目のステップで正しい順序で値を配置する方がよい(---から借りる Pythonの属性によってオブジェクトのリストからオブジェクトを選択する方法 ):

shoes = Shoe.query.filter(Shoe.id.in_(my_list_of_ids)).all()
[next(s for s in shoes if s.id == id) for id in my_list_of_ids]

これは、IDが一意であることを前提としています(IDはあなたのケースでは固有である必要があります)。最初のメソッドは、同じIDを持つ要素が複数ある場合に例外を発生させます。

14
Rob

過去にこの問題を解決した1つの方法は、 SQL CASE式 を使用して、行を返す順序をデータベースに通知することです。あなたの例を使用して:

from sqlalchemy.sql.expression import case

ordering = case(
    {id: index for index, id in enumerate(my_list_of_ids)},
    value=Shoe.id
 )
Shoe.query.filter(Shoe.id.in_(my_list_of_ids)).order_by(ordering).all()
12
bjmc

また、MySQLデータベースを使用して同じ問題があります。これは私がやったことです:

my_list = [13,14,5,6,7]
# convert my_list to str
my_list_str = ','.join(map(str, my_list))

そして、これは私のクエリがどのように見えるかです:

checkpoints = (
    db_session.query(Checkpoint)
    .filter(Checkpoint.id.in_(my_list))
    .order_by('FIELD(id, ' + my_list_str + ')')
    .all()
)

FIELD()はMySQLのネイティブ関数です。

編集:したがって、クエリは次のようになります。

my_list_of_ids_str = ','.join(map(str, my_list_of_ids)) 
Shoe.query.filter(Shoe.id.in_(my_list_of_ids)).order_by('FIELD(id, ' + my_list_of_ids_str + ')').all()

乾杯

0