How do I SELECT WHERE IN VALUES with tuples in Python sqlite3?

jmkjaer :

I have an SQLite database with three columns, and I'm trying to use parameter substitution for tuples to SELECT rows. This is my table:

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

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

I know how to substitute with non-tuples, but I cannot figure out how to do it with tuples.

Based on this answer, I thought I simply had to substitute each and every value across the list of tuples:

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)

but then I get the error

ProgrammingError: Incorrect number of bindings supplied. The current statement uses 10, and there are 5 supplied.

Obviously this means that I only need one question mark per tuple, right?:

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)

But then I get this error:

OperationalError: sub-select returns 1 columns - expected 2

I cannot insert the values manually like in the linked answer, since I don't know what the list parameter contains. This means that I need to do some kind of ",".join() based on the length of the list, but I'll figure that out once I know how to do substitution with a fixed-length list.

How would I do this?

blhsing :

Using the str.join method is indeed a good way to achieve this, given the lack of native support for container-based placeholders in SQL engines:

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)

where, with the given values:

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

would expand into:

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

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=279200&siteId=1