如何将变量添加到sqlalchemy查询过滤器并将其转换为字符串查询?

时间:2015-12-04 01:48:53

标签: python pandas flask sqlalchemy

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

我遇到的问题是我正在尝试在过滤器中使用变量,当我将其转换为查询字符串时,它会将变量保留为out,就像我没有提供值一样。这会产生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注入的某种安全措施或类似的东西,但我似乎无法弄清楚如何在字符串查询中获取变量值。

1 个答案:

答案 0 :(得分:0)

好吧,经过几个小时的挖掘(还有一些休息),我设法弄明白了。

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

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

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

解决了最初的问题之后,我遇到了过滤器的问题。事实证明,当你试图在sqlite中将日期时间转换为日期cast(Entry.week_end,Date)时(这是我需要做的以使过滤器正常工作),它只返回年份并将抛出一个ValueError,说它可以' t解析日期字符串。 为了解决这个问题,我发现您可以将日期函数应用于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])