首页 > 解决方案 > 如何在 Python sqlite3 中使用元组选择 WHERE IN VALUES?

问题描述

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

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

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

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

基于这个答案,我想我只需要替换元组列表中的每个值:

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()根据列表的长度做一些事情,但是一旦我知道如何用固定长度的列表进行替换,我就会弄清楚这一点。

我该怎么做?

标签: pythonsqlpython-3.xsqlitesubstitution

解决方案


鉴于 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 (?,?),(?,?),(?,?),(?,?),(?,?))

推荐阅读