Фильтрация SQL-запросов на основе параметров с более чем одним значением - PullRequest
0 голосов
/ 13 сентября 2018

Я пытаюсь создать SQL, который должен быть отфильтрован по двум параметрам (2 столбца), а второй столбец должен соответствовать нескольким значениям.

Ниже приведен SQL, который я построил до сих пор (спасибо за помощь Martijn Pieters )

import psycopg2
import pandas as pd
import datetime

# Connecting to db

con = psycopg2.connect(db_details)
cur = con.cursor()
cur.execute("select * from sales limit 10")
rows = cur.fetchall()

params = {'earliest': datetime.datetime.today() - datetime.timedelta(days=7),
      'store_name': 'store_1', 'store_2'}

df = pd.read_sql("""
     select store_name,count(*) from sales 
     where created_at >= %(earliest)s
     and store_name = %(store_name)s""",
 params=params, con=con)

В приведенном выше SQL есть один параметр даты, который используется в предложении where, и я добавил еще один параметр, а именно store_name , где строки соответствуют одному из двух значений.

Хотелось бы узнать, как я могу добавить этот дополнительный параметр к существующему запросу.

Я попытался создать параметр (похожий на фильтр даты) и передать его в существующий запрос, но получил синтаксическую ошибку, когда я дал ему два значения:

    'store_name': 'store_1', 'store_2'}
                                      ^
SyntaxError: invalid syntax

указывает на поле params.

Ответы [ 2 ]

0 голосов
/ 13 сентября 2018

У вас есть две проблемы:

  • Вы использовали неверный синтаксис Python;запятая в словаре разделяет пары ключ-значение, поэтому строка 'store_2' будет другой парой ключ-значение, но в ней отсутствуют части : value.Если вы хотите определить значение с более чем одной строкой, вам придется использовать кортеж или список там, где вы явно используете (...) или [...] для отделения этого синтаксиса от обозначения key: value, key: value:

    params = {
        'earliest': datetime.datetime.today() - datetime.timedelta(days=7),
        'store_name': ('store_1', 'store_2'),  # tuple with two values
    }
    
  • Вообще говоря, параметры SQL могут работать только с отдельными значениями .Параметру store_name может быть присвоено только одно значение, а не последовательность значений.Это связано с тем, что параметры SQL являются мостом между запросом SQL и динамическими значениями, которые будут использоваться в этом запросе, а параметры предназначены для использования в качестве заполнителя для каждого отдельного динамического значения.

    Тем не менее,psycopg2 библиотека специально поддерживает кортежи , однако это исключение для большинства библиотек баз данных Python.

    Далее, если вы хотите фильтровать строки по совпадению либо 'store_1', либо 'store_2'правильный синтаксис SQL - использовать два store_name = ... теста с OR между ними и круглыми скобками (чтобы отделить эту часть от теста date, связанного с AND с тестом имени магазина), или с помощью store_name IN ('store_1', 'store_2').Тест IN сравнивает имя столбца с несколькими значениями, перечисленными в скобках (...).

Учитывая, что вы используете psycopg2 здесь, вы можете избежать использования store_name ключ ссылается на значение кортежа, но вам нужно использовать IN для вашего запроса:

params = {
    'earliest': datetime.datetime.today() - datetime.timedelta(days=7),
    'store_name': ('store_1', 'store_2')
}

df = pd.read_sql("""
     SELECT store_name, count(*) FROM sales 
     WHERE created_at >= %(earliest)s
     AND store_name IN %(store_name)s""",
     params=params, con=con)

На отдельном примечании: функция pd.read_sql() [явно заявляет, что при использовании a поддерживается только sqliteСоединение с DBAPI] (Если объект DBAPI2, поддерживается только sqlite3):

Если объект DBAPI2, поддерживается только sqlite3.

Вы используете такой объект;большинство адаптеров баз данных Python являются библиотеками DBAPI2;DBAPI2 - это стандарт Python для таких библиотек .

Вместо этого вам действительно следует использовать строку соединения SQLAlchemy .Ваш код оказывается работающим, потому что вы никогда не пытаетесь записать какие-либо данные обратно в базу данных, а объекты соединения и курсора psycopg в значительной степени совместимы с версиями библиотеки sqlite3, но вы можете столкнуться с проблемами в будущем.

0 голосов
/ 13 сентября 2018

Не понимаю, почему это не сработает:

params = {'earliest': datetime.datetime.today() - datetime.timedelta(days=7),
          'store_name': '<put what you want here>'}

df = pd.read_sql("""
         select store_name,count(*) from sales 
         where created_at >= %(earliest)s
         and store_name = %(store_name)s""",
     params=params, con=con)

Поскольку вам нужны два магазина, это немного сложнее.

Это должно работать:

params = {'earliest': datetime.datetime.today() - datetime.timedelta(days=7),
          'store_names': ','.join(('store_1', 'store_2'))}

df = pd.read_sql("""
         select store_name,count(*) from sales 
         where created_at >= %(earliest)s
         and store_name in (%(store_names)s)""",
     params=params, con=con)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...