解决 select 查询中的 SQLite 参数限制

Work around the SQLite parameter limit in a select query

我有一个 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 查询,然后以某种方式组合它们?

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,然后将它们作为列表整体传递到第二个查询中。但由于第一个查询 ("all my friends") 本身就是一个查询,我们可以将它们组合起来。您也可以使用 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 进行过滤。