【问题标题】:How do I SELECT WHERE IN VALUES with tuples in Python sqlite3?如何在 Python sqlite3 中使用元组选择 WHERE IN VALUES?
【发布时间】:2020-06-23 19:36:24
【问题描述】:

我有一个包含三列的 SQLite 数据库,我正在尝试使用参数替换元组到 SELECT 行。这是我的桌子:

conn = sqlite3.connect("SomeDb.sqlite3")

conn.execute("""
CREATE TABLE RoadSegmentDistribution(
    Source INTEGER,
    Destination INTEGER,
    Distribution TEXT
)
""")

我知道如何用非元组替换,但我不知道如何用元组替换。

基于this answer,我认为我只需替换元组列表中的每个值:

for e in conn.execute("""
    SELECT *
    FROM RoadSegmentDistribution
    WHERE (
        Source, Destination
    ) IN (VALUES (?,?), (?,?), (?,?), (?,?), (?,?))
    """,
    [(1, 2),(2, 3),(4, 5),(6, 7),(8, 9)]
):
    print(e)

然后我得到错误

ProgrammingError:提供的绑定数量不正确。当前语句使用 10,提供了 5 个。

显然这意味着每个元组只需要一个问号,对吧?:

for e in conn.execute("""
    SELECT *
    FROM RoadSegmentDistribution
    WHERE (
        Source, Destination
    ) IN (VALUES (?), (?), (?), (?), (?))
    """,
    [(1, 2),(2, 3),(4, 5),(6, 7),(8, 9)]
):
    print(e)

然后我得到这个错误:

OperationalError:子选择返回 1 列 - 预期为 2

我不能像在链接的答案中那样手动插入值,因为我不知道列表参数包含什么。这意味着我需要根据列表的长度来做某种",".join(),但是一旦我知道如何用固定长度的列表进行替换,我就会弄清楚这一点。

我该怎么做?

【问题讨论】:

  • 只使用一个问号“IN (VALUES?)”怎么样?
  • @z44.nelther 不幸的是,这给了我一个OperationalError: near "?": syntax error

标签: python sql python-3.x sqlite substitution


【解决方案1】:

考虑到 SQL 引擎中缺乏对基于容器的占位符的原生支持,使用 str.join 方法确实是实现这一目标的好方法:

values = [(1, 2), (2, 3), (4, 5), (6, 7), (8, 9)]

for e in conn.execute(f"""
    SELECT *
    FROM RoadSegmentDistribution
    WHERE (
        Source, Destination
    ) IN (VALUES {','.join(f'({",".join("?" * len(t))})' for t in values)})
    """,
    [i for t in values for i in t]
):
    print(e)

在哪里,使用给定的values

f"""
    SELECT *
    FROM RoadSegmentDistribution
    WHERE (
        Source, Destination
    ) IN (VALUES {','.join(f'({",".join("?" * len(t))})' for t in values)})
"""

将扩展为:

SELECT *
FROM RoadSegmentDistribution
WHERE (
    Source, Destination
) IN (VALUES (?,?),(?,?),(?,?),(?,?),(?,?))

【讨论】:

  • 这也是我的第一个猜测,但我只是得到了第一个列出的ProgrammingError: Incorrect number of bindings supplied. The current statement uses 10, and there are 5 supplied.
  • 糟糕,刚刚修好了。
  • 有效!为了正确测试它,我必须在接受之前修复一些命令,但它可以工作。非常感谢!
  • 我的错...(--在这里插入一个手掌--)。我在帖子开头专注于OP错误的结论并错过了底部
【解决方案2】:

@jmkjaer:不是答案,但需要澄清

反之亦然 -
您的查询需要 10 个绑定,它并不关心它们在查询中的分布方式。
您需要做的就是提供一个包含 10 个元素的列表:

[1,2, 2,3, 4,5, 6,7, 8,9]

演示

import sqlite3

conn = sqlite3.connect(':memory:')
vals = [(1, 2),(2, 3),(4, 5),(6, 7),(8, 9)]
flat_vals = [e for t in vals for e in t ]

for e in conn.execute("values (?,?),(?,?),(?,?),(?,?),(?,?)",flat_vals):
    print(e)


(1, 2)
(2, 3)
(4, 5)
(6, 7)
(8, 9)

【讨论】:

  • 使用sum 连接一个元组序列是非常低效的。
  • 要么像我的例子那样使用列表理解,要么像itertools.chain 官方documentation 所说的那样。 sum 效率极低,因为它为每个加法操作创建一个新元组。
  • @DavidדודוMarkovitz 谢谢!我不知道为什么我没有意识到我只需要将我的元组列表扁平化为一个列表。我不知何故想到查询中的元组必须与输入列表中的元组相对应。下次查询时,我会记住您的回答!
【解决方案3】:

您可以尝试以不同的方式构建查询并根据您传递的参数生成它。

query_head ="SELECT * FROM RoadSegmentDistribution WHERE "
params = [(1, 2),(2, 3),(4, 5),(6, 7),(8, 9)]

def add_condition(pair):
    condition = f"(Source = {pair[0]} AND Destination = {pair[1]})"
    return condition

def build_query(query_head,params):
    conditions = ' OR '.join([add_condition(param) for param in params])
    query = query_head+conditions
    return query

query = build_query(query_head,params)
conn.execute(query)

【讨论】:

  • 这似乎比我目前使用的更好!我明天得试试!但不幸的是,我必须向@blhsing 给出答案,因为它对我有用,无需进一步重新排序。不过非常感谢!
  • 完全没有问题,也没有难过的感觉。我很高兴我的回答能够提供帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-22
  • 2013-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多