我在使用 Peewee 和 MySQL 时遇到了问题。基本上我想过滤用户的日志并将其分类到过去 8 周(例如第 0 周到第 7 周)。 结果应该如下所示:
{ 'userid': 1, 'week':1, 'bin': ?},
...
{ 'userid': 1, 'week':7, 'bin': ?},
{ 'userid': 2, 'week':0, 'bin': ?},
...
etc.
但是,我想确保即使用户在特定一周的日志中没有条目,它仍然显示为 'bin': 0。我会使用 OUTER JOIN,但我没有相应的“week”表来外部连接与。 在 SQL 中,我会执行以下操作:
WITH weeks (week) AS (
VALUES ROW(0),ROW(1),ROW(2),ROW(3),ROW(4),ROW(5),ROW(6),ROW(7)
)'
然后在连接中使用“周”。但是我不知道如何在 peewee 中做到这一点。如果我创建一个“RawQuery”,我无法像使用常规查询一样使用它进行连接(它没有 .c 来访问字段或 .select())。
我最终在没有太多记录的表上使用了这样的脏修复:
max_weeks = 8
weeks = (
MyTable.select(
(fn.MOD(MyTable.id,max_weeks)).alias("week")
).distinct()
)
但我更愿意以正确的方式去做。
我必须在这里指定,我的要求是我只对数据库进行一个查询(由多个子查询组成),并且周数(在本例中为8)是可变的。另外,我对数据库具有只读权限。
我没有方便的 MySQL,因为我使用 MariaDB,它使用稍微不同的语法,但希望这样的东西应该可以工作:
from peewee import *
from peewee import NodeList, CommaNodeList, CTE
db = MySQLDatabase('peewee_test')
class Reg(db.Model):
value = IntegerField()
db.create_tables([Reg])
Reg.create(value=1)
weeks = CommaNodeList([fn.ROW(i) for i in range(8)])
cte = CTE('weeks', NodeList([SQL('VALUES'), weeks]), columns=['week'])
# Just a simple cartesian product of Reg x Weeks - in your example
# you would be performing a join instead.
query = Reg.select(Reg.value, cte.c.week).from_(Reg, cte).with_cte(cte)
print(query.sql())
for row in query:
print(row.value, row.week)
生成的SQL:
WITH `weeks` (`week`) AS (
VALUES ROW(0), ROW(1), ROW(2), ROW(3),
ROW(4), ROW(5), ROW(6), ROW(7))
SELECT `t1`.`value`, `weeks`.`week`
FROM `reg` AS `t1`, `weeks`