根据具有多个值的参数过滤SQL查询

时间:2018-09-13 10:31:13

标签: python sql python-3.x postgresql

我正在尝试构建一个需要用两个参数(2列)过滤的SQL,第二列需要匹配多个值。

下面给出的是我到目前为止构建的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有一个date参数,该参数在where子句中使用,我又添加了一个参数 store_name ,其中行与两个值之一匹配。

想知道如何将这个附加参数添加到现有查询中。

我试图创建一个参数(类似于日期过滤器)并将其传递给现有查询,但是当我给它两个值时会出现语法错误:

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

指向params字段。

2 个答案:

答案 0 :(得分:2)

您有两个问题:

  • 您使用了无效的Python语法;字典中的逗号分隔键值对,因此'store_2'字符串将是另一个键值对,但缺少: value部分。如果您想使用多个字符串定义一个值,则必须在其中使用元组或列表,如果您明确使用(...)[...]将该语法与{{ 1}}表示法:

    key: value, key: value
  • 通常来说,SQL参数只能与单个值一起使用。 params = { 'earliest': datetime.datetime.today() - datetime.timedelta(days=7), 'store_name': ('store_1', 'store_2'), # tuple with two values } 参数只能给一个值,而不是一个值序列。这是因为SQL参数是SQL查询和该查询中要使用的动态值之间的桥梁,并且这些参数旨在充当每个个体动态值的占位符。

    也就是说,store_namespecifically supports tuples是大多数Python数据库库的例外。

    接下来,如果要在匹配psycopg2'store_1'的情况下过滤行,则正确的SQL语法是使用两个'store_2'测试,并且它们之间使用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) 函数[明确指出在使用DBAPI连接时仅支持sqlite](如果为DBAPI2对象,则仅支持sqlite3):

  

如果是DBAPI2对象,则仅支持sqlite3。

您正在使用这样的对象;大多数Python数据库适配器都是DBAPI2库; DBAPI2是Python standard for such libraries

您实际上应该使用SQLAlchemy connection string代替。代码之所以能够运行,是因为您从未尝试将任何数据写回到数据库,并且psycopg连接和游标对象与sqlite3库版本在很大程度上兼容,但是您可能会遇到麻烦。

答案 1 :(得分:-1)

我不明白为什么这行不通:

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)