Как ВЫБРАТЬ ГДЕ В ЗНАЧЕНИЯХ с кортежами в Python sqlite3? - PullRequest
4 голосов
/ 11 марта 2020

У меня есть база данных 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: sub-select возвращает 1 столбец - ожидается 2

Я не могу вставить значения вручную, как в связанном ответе, так как я не знаю что содержит параметр списка. Это означает, что мне нужно сделать что-то вроде ",".join() в зависимости от длины списка, но я пойму это, когда узнаю, как выполнить замену со списком фиксированной длины.

Как бы Я делаю это?

Ответы [ 3 ]

3 голосов
/ 11 марта 2020

Использование метода str.join действительно хороший способ для достижения этой цели, учитывая отсутствие встроенной поддержки заполнителей на основе контейнеров в SQL движках:

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 (?,?),(?,?),(?,?),(?,?),(?,?))
1 голос
/ 11 марта 2020

@ jmkjaer: не ответ, но необходим для уточнения

Вы получили его наоборот -
Ваш запрос требует 10 привязок, и ему все равно как они распределены по запросу.
Все, что вам нужно сделать, это предоставить список из 10 элементов:

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

demo

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)
1 голос
/ 11 марта 2020

Вы можете попытаться структурировать свой запрос по-другому и сгенерировать его на основе переданных вами параметров.

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...