问题描述
我正在建立一个查询,该查询会根据频率字段进行过滤。现在,频率不是模型字段,而是从持续时间和计数得出的带注释的值。这是基于frequency = duration / number of times stuff happened
这个非常基本的想法。
(非常)简化的模型如下:
import uuid
class Actor(AbstractBaseUser):
id = models.UUIDField(_('UUID'),default=uuid.uuid4,primary_key=True)
class Event(models.Model):
actor = models.ForeignKey(Actor,null=True,blank=True,on_delete=models.CASCADE)
foo = models.CharField(_('Foo'),max_length=10,null=True)
bar = models.CharField(_('Bar'),null=True)
when = models.DateTimeField(_('When'),blank=True)
查询背后的想法是:
- 每个演员都带有 event_count 注释:它是父对象的Event对象的数量
- 每个演员的注释都带有 first_event_datetime :其最早的子事件对象的日期时间
- 每个演员都用 duration_over 进行注释:Now()(数据库函数)与first_event_datetime之间的持续时间
- 在考虑的时间段 event_frequency 中,每个演员都以事件的“ event_frequency”进行注释:duration_over / event_count
请记住,查询的构建方式如下:
from django.db import models
from django.db.models import Q,Sum,Avg,F,Count,OuterRef,Subquery,Exists,Value,ExpressionWrapper
from django.db.models.functions import Coalesce,Now,Mod,Cast
actors = Actor.objects.annotate(
event_count=Coalesce(Subquery(
Event.objects.filter(
actor__pk=OuterRef('pk')
).values(
'actor__pk'
).order_by(
'actor__pk'
).annotate(
count=Count('pk',distinct=True)
).values(
'count'
),output_field=models.IntegerField()
),0)
).annotate(
first_event_datetime=Subquery(
Event.objects.filter(
actor__pk=OuterRef('pk')
).order_by(
'when'
).values(
'when'
)[:1],output_field=models.DateTimeField()
)
).annotate(
duration_over=ExpressionWrapper(
Now() - F('first_event_datetime'),output_field=models.DurationField()
)
).annotate(
event_frequency=ExpressionWrapper(
F('duration_over') / F('transaction_count'),output_field=models.DurationField()
)
).filter(
# might want to avoid db-side divide by zero? :-/
event_count__gte=1,# or any other timedelta
event_frequency__gt=timedelta(days=2)
)
结果如下:
Traceback (most recent call last):
File "<...>main/env/lib/python3.6/site-packages/django/db/backends/utils.py",line 84,in _execute
return self.cursor.execute(sql,params)
File "<...>main/env/lib/python3.6/site-packages/django/db/backends/MysqL/base.py",line 73,in execute
return self.cursor.execute(query,args)
File "<...>main/env/lib/python3.6/site-packages/MysqLdb/cursors.py",line 209,in execute
res = self._query(query)
File "<...>main/env/lib/python3.6/site-packages/MysqLdb/cursors.py",line 315,in _query
db.query(q)
File "<...>main/env/lib/python3.6/site-packages/MysqLdb/connections.py",line 239,in query
_MysqL.connection.query(self,query)
MysqLdb._exceptions.ProgrammingError: (1064,"You have an error in your sql Syntax; check the manual that corresponds to your MysqL server version for the right Syntax to use near '/ COALESCE((SELECT COUNT(disTINCT U0.`id`) AS `count` FROM `event_event' at line 1")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<console>",line 1,in <module>
File "<...>main/env/lib/python3.6/site-packages/django/db/models/query.py",line 263,in __repr__
data = list(self[:REPR_OUTPUT_SIZE + 1])
File "<...>main/env/lib/python3.6/site-packages/django/db/models/query.py",line 287,in __iter__
self._fetch_all()
File "<...>main/env/lib/python3.6/site-packages/django/db/models/query.py",line 1308,in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "<...>main/env/lib/python3.6/site-packages/django/db/models/query.py",line 53,in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch,chunk_size=self.chunk_size)
File "<...>main/env/lib/python3.6/site-packages/django/db/models/sql/compiler.py",line 1156,in execute_sql
cursor.execute(sql,params)
File "<...>main/env/lib/python3.6/site-packages/django/db/backends/utils.py",line 98,in execute
return super().execute(sql,line 66,in execute
return self._execute_with_wrappers(sql,params,many=False,executor=self._execute)
File "<...>main/env/lib/python3.6/site-packages/django/db/backends/utils.py",line 75,in _execute_with_wrappers
return executor(sql,many,context)
File "<...>main/env/lib/python3.6/site-packages/django/db/backends/utils.py",params)
File "<...>main/env/lib/python3.6/site-packages/django/db/utils.py",line 90,in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "<...>main/env/lib/python3.6/site-packages/django/db/backends/utils.py",query)
django.db.utils.ProgrammingError: (1064,"You have an error in your sql Syntax; check the manual that corresponds to your MysqL server version for the right Syntax to use near '/ COALESCE((SELECT COUNT(disTINCT U0.`id`) AS `count` FROM `event_event' at line 1")
我尝试将event_frequency
注释值更改为以下内容:
-
Cast(F('duration_over'),models.DurationField()) / Cast(F('event_count'),models.IntegerField())
- 以及
Cast
和ExpressionWrapper
...的其他类似组合。
无济于事。
有什么想法吗?
非常感谢!
SELECT `actor`.`id`
FROM `actor`
WHERE (
COALESCE(
(
SELECT COUNT(disTINCT U0.`id`) AS `count`
FROM `event` U0
WHERE U0.`actor_id` = `actor`.`id`
GROUP BY U0.`actor_id`
ORDER BY NULL
),0
) >= 1
AND (
INTERVAL
TIMESTAMPDIFF(
MICROSECOND,(
SELECT U0.`transaction_datetime`
FROM `event` U0
WHERE U0.`actor_id` = `actor`.`id`
ORDER BY U0.`transaction_datetime`
ASC LIMIT 1
),CURRENT_TIMESTAMP
) MICROSECOND
/
COALESCE(
(
SELECT COUNT(disTINCT U0.`id`) AS `count`
FROM `event` U0
WHERE U0.`actor_id` = `actor`.`id`
GROUP BY U0.`actor_id`
ORDER BY NULL
),0
)
) > 86400000000
)
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)