【问题标题】:Pandas read_sql with multiple parameters and lists具有多个参数和列表的 Pandas read_sql
【发布时间】:2020-01-09 13:32:33
【问题描述】:

我有以下脚本:

now = dt.datetime.now()
date_filter = now - timedelta(days=3)
list_ids = [1,2,3]
dq_connection = mysql.connector.connect(user='user', password='pass', host='localhost', database='db')
engine = create_engine('localhost/db')
cursor = connection.cursor(buffered=True)
query = ('''
SELECT *
FROM (SELECT * FROM myTable1 WHERE id in {%s}
WHERE date >= %s;
''')
df = pd.read_sql_query(query, connection,params=(list_ids,date_filter,))

我想在我的查询中有两个过滤器: 1) 列出我在 list_ids 上的所有 ID 2) 只过滤 date_filter 之前的日期。

第二个过滤器我可以做到,但是当我尝试使用得到的列表时:

pandas.io.sql.DatabaseError: Execution failed on sql

我做错了什么?

【问题讨论】:

    标签: python sql pandas filter


    【解决方案1】:

    因为IN子句接收多个值,你需要用必要数量的占位符调整prepared statement,%s,然后解包func(*list)的参数列表。另外,WHERE 子句都不需要子查询。

    query = '''SELECT * FROM myTable1 
               WHERE id in (%s, %s, %s) AND date >= %s;
            '''
    
    df = pd.read_sql_query(query, connection, params=(*list_ids, date_filter))
    

    对于等于列表长度的动态占位符,集成str.join

    placeholders = ", ".join(["%s" for _ in list_ids])
    
    query = '''SELECT * FROM myTable1 
               WHERE id in ({}) AND date >= %s;
            '''.format(placeholders)
    
    df = pd.read_sql_query(query, connection, params=(*list_ids, date_filter))
    

    【讨论】:

    • *list_ids 在这里做什么?为什么不只是list_ids
    • @DaveRGP,作为解决方案中的文本提到,asterisk unpacks the list,因此您可以将列表中的每个字符串与 SQL 语句中的相应%s 匹配。否则,您将尝试为 4 个参数(期望 4 个标量)绑定 2 个对象(一个是可迭代对象而不是标量),因此数据库引擎会出错。
    • 非常好,有一条评论 - 您不需要将连接中的表达式明确区分为列表理解。对于某些语法糖,您可以将表达式保留为 placeholders = ", ".join("%s" for _ in list_ids)
    • @KeironStoddart,说得好。从这个问题开始我就知道了,join 允许生成器。
    猜你喜欢
    • 2014-08-16
    • 1970-01-01
    • 2016-12-03
    • 1970-01-01
    • 2015-04-28
    • 1970-01-01
    • 2021-08-15
    • 1970-01-01
    相关资源
    最近更新 更多