简体   繁体   English

Sqlalchemy按列表中的字段过滤但保留原始订单?

[英]Sqlalchemy filter by field in list but keep original order?

I have a Shoe model like this: 我有一个像这样的鞋子模型:

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

I have a list of ids like ids = [2,1,3] and when I query on the Shoe model such that the results have ids in the 'ids' list, I want back: [{id:2, asin:"111"},{id:1, asin:"113"},{id:3, asin:"42"}] but the problem is that using the following query statement doesn't preserve the original order, the results will come back random. 我有一个像ids = [2,1,3]的id列表,当我在Shoe模型上查询结果在'ids'列表中有id时,我想回来:[{id:2,asin:“ 111“},{id:1,asin:”113“},{id:3,asin:”42“}]但问题是使用以下查询语句不保留原始顺序,结果将会到来随机回来。 How do I keep the order of the list I filtered by? 如何保持我过滤的列表顺序?

Incorrect one: Shoe.query.filter(Shoe.id.in_(my_list_of_ids)).all() 不正确的一个: Shoe.query.filter(Shoe.id.in_(my_list_of_ids)).all()

If you have a reasonable small list of ids, you could just perform SQL queries on each id individually: 如果你有一个合理的小ID列表,你可以单独对每个id执行SQL查询:

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

For a large number of ids, SQL queries will take a long time. 对于大量ID,SQL查询将花费很长时间。 Then you are better off with a single query and putting the values in the correct order in a second step (borrowed from how to select an object from a list of objects by its attribute in python ): 然后,您最好使用单个查询并在第二步中以正确的顺序放置值(借用于如何通过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]

This is assuming the id's are unique (which they should be in your case). 这假设id是唯一的(它们应该在你的情况下)。 The first method will raise an exception if there are multiple elements with the same id. 如果有多个具有相同id的元素,则第一种方法将引发异常。

One way I've solved this problem in the past is by using a SQL CASE expression to tell the database in what order I'd like the rows returned. 我过去解决这个问题的一种方法是使用SQL CASE表达式告诉数据库我想要返回的行的顺序。 Using your example: 使用你的例子:

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

I also have the same problem using a MySQL database. 使用MySQL数据库时也遇到了同样的问题。 This is what I did: 这就是我做的:

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

And this is how my query looks like: 这就是我的查询的样子:

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

FIELD() is a native function in MySQL. FIELD()是MySQL中的本机函数。

EDIT: So your query should look like this: 编辑:所以你的查询应该是这样的:

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

Cheers 干杯

What do you mean when you say "original order"? 当你说“原始订单”时,你是什么意思? Database doesn't have such thing as "original order". 数据库没有“原始订单”这样的东西。 If you need some order, you must add something like: 如果您需要订单,则必须添加以下内容:

.order_by(Shoe.id.desc())

If you don't specify the order, it's still possible that you get ordered data from database. 如果您未指定订单,则仍有可能从数据库获取有序数据。 But in this case, database just uses order that doesn't needs any unnecessary data manipulation. 但在这种情况下,数据库只使用不需要任何不必要的数据操作的顺序。 It's just looks like an ordered data, but it isn't. 它看起来像一个有序的数据,但事实并非如此。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM