解决选择查询中的SQLite参数限制

时间:2019-02-12 14:11:33

标签: peewee

我有一个GUI应用程序,其中包含人员列表,其中包含该人员的数据库ID及其属性。像这样:

+----+------+
| ID | Name |
+----+------+
|  1 | John |
|  2 | Fred |
|  3 | Mary |
[...]

此列表可以被过滤,因此人数和类型不时取决于。要获取Peewee Person对象的列表,我首先获取可见ID的列表,并使用以下查询:

ids = [row[0] for row in store]
Person.select().where(Person.id.in_(ids))

依次翻译为以下SQL:

('SELECT "t1"."id", "t1"."name" FROM "person" AS "t1" WHERE ("t1"."id" IN (?, ?, ?, ...))', [1, 2, 3, ...])

这在有1000人以上的Windows上引发OperationalError: too many SQL variables错误。 Peewee和SQLite文档中对此进行了记录。在线给出的解决方法通常与批量插入以及将操作拆分为多个块的方式有关。可以通过上述SELECT ... WHERE ... IN查询来解决此限制吗?

在列表理解中获取单独的对象太慢了:

people = [Person.get_by_id(row[0]) for row in store]

也许可以将ID列表拆分为最多1000个项目,对每个块使用select查询,然后以某种方式组合它们?

1 个答案:

答案 0 :(得分:0)

ID来自哪里?最佳答案当然是避免使用那么多参数。例如,如果您的ID列表可以表示为某种查询,则只需编写一个子查询,例如

my_friends = (Relationship
              .select(Relationship.to_user)
              .where(Relationship.from_user == me))
tweets_by_friends = Tweet.select().where(Tweet.user.in_(my_friends))

在上面,我们可以从第一个查询中获取所有用户ID,然后将它们作为列表传递给第二个查询。但是,由于第一个查询(“我所有的朋友”)本身就是一个查询,因此我们可以将它们组成。您也可以使用JOIN代替子查询,但是希望您能理解这一点。

如果这不可能,并且您认真地拥有一个超过1000个ID的列表...这样的列表在GUI应用程序中如何有用?超过1000种东西很多。

要尝试回答您提出的问题-您必须将它们拼凑起来。没关系只是:

user_ids = list_of_user_ids
accum = []
# 100 at a time.
for i in range(0, user_ids, 100):
    query = User.select().where(User.id.in_(user_ids[i:i+100]))
    accum.extend([user for user in query])
return accum

但是,严重的是,我认为您实现此方法的方式存在问题,甚至有必要过滤许多id。