【问题标题】:How do I add a variable to a sqlalchemy query filter and convert it to a string query?如何将变量添加到 sqlalchemy 查询过滤器并将其转换为字符串查询?
【发布时间】:2016-03-08 20:51:57
【问题描述】:

我有一个汇总查询,我试图将它放入 Flask 应用程序中的 pandas 数据框中。我已经想出了如何将 sqlalchemy 查询转换为 pandas 可以读入数据帧的字符串查询。该变量具有已转换为字符串的日期值。

我遇到的问题是我试图在过滤器中使用一个变量,当我将它转换为查询字符串时,它会将变量排除在外,就像我没有提供值一样。这会导致 sqlalchemy.exc.programmingerror。

这是我的日期变量:

this_week = datetime.strftime(get_friday(datetime.now().date()),'%m/%d/%Y')

get_friday() 函数只是从给定日期获取一周中的星期五。在这种情况下,我只关注当前的一周。

这是我设置为变量的查询:

grouped_entries = Entry.query \
  .with_entities(Entry.entry_date.label('entry_date'), \
    Entry.client.label('client'),Entry.day.label('day'), \
    func.sum(Entry.total_time).label('time_sum')) \
  .filter(Entry.week_end == this_week) \
  .group_by(Entry.client,Entry.entry_date,Entry.day) \
  .order_by(Entry.entry_date.asc())

这是将查询转换为字符串查询以读入数据帧的 pandas 代码:

pd.read_sql(str(grouped_entries.statement.compile(dialect=sqlite.dialect())), db.engine)

这是我尝试运行它时遇到的错误:

sqlalchemy.exc.ProgrammingError: (sqlite3.ProgrammingError) Incorrect number of bindings supplied. The current statement uses 1, and there are 0 supplied.[SQL: 'SELECT entry.entry_date AS entry_date, entry.client AS client, entry.day AS day, sum(entry.total_time) AS time_sum \nFROM entry \nWHERE entry.week_end = ? GROUP BY entry.client, entry.entry_date, entry.day ORDER BY entry.entry_date ASC']

我知道该查询可以作为 sqlalchemy 查询单独运行,但是当它转换为字符串查询时,它会添加一个 ?代替 filter/where 子句中的变量值。我想这是 sql 注入或类似的某种安全措施,但我似乎无法弄清楚如何在字符串查询中获取变量值。

【问题讨论】:

  • 你试过print grouped_entries。这应该打印原始 SQL,并且您应该查看您使用的变量在转换之前是否被正确解析。
  • @shifloni 是的,我检查了查询的字符串输出。它显示如下: SELECT entry.client AS client, entry.day AS day, sum(entry.total_time) AS time_sum FROM entry WHERE entry.week_end = :week_end_1 GROUP BY entry.client, entry.day ORDER BY entry.entry_date ASC
  • 我在pandas中找到了read_sql函数的params特性。我可以使用它来将 this_week 变量添加到查询中,但现在我没有得到任何结果,即使应该显示结果。
  • 您确定数据类型匹配了吗?
  • @shifloni 我确实在获得要正确插入查询的变量后检查了这一点。它需要一个日期时间对象,所以我更新了this_week 变量以确保它也是一个日期时间对象。

标签: python pandas flask sqlalchemy


【解决方案1】:

好吧,经过几个小时的挖掘(和一些休息),我设法弄清楚了。

我发现将变量插入语句的最简单方法是利用 pandas 中的 read_sql 函数并将变量设置为参数。

data = pd.read_sql(str(grouped_entries), db.engine, params=[this_week])

这会将变量插入到字符串查询中。

在解决了最初的问题后,我遇到了过滤器问题。事实证明,当您尝试在 sqlite 中将日期时间转换为日期 cast(Entry.week_end,Date) 时(这是我需要做的以使过滤器正常工作),它只返回年份并且会抛出一个 ValueError 说它无法解析日期字符串。 为了解决这个问题,我发现你可以在 sqlalchemy 中对列应用一个日期函数,类似于this issue

这是我的最终代码:

this_week = datetime.strftime(get_friday(datetime.now()),'%Y-%m-%d')
grouped_entries = Entry.query \
                       .with_entities(Entry.client.label('client'), \
                         Entry.day.label('day'), \
                         func.sum(Entry.total_time).label('time')) \
                       .filter(func.DATE(Entry.week_end) == this_week) \
                       .group_by(Entry.client,Entry.day) \
                       .order_by(Entry.day.asc())
data = pd.read_sql(str(grouped_entries), db.engine, params=[this_week])

【讨论】:

    猜你喜欢
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多