我有一个汇总查询,我试图将其放入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注入的某种安全措施或类似的东西,但我似乎无法弄清楚如何在字符串查询中获取变量值。
答案 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])