我有以下基本可行的SQL。我将如何在Django ORM中表示这一点?我想避免运行完整的原始查询
我不知道如何在Django ORM中进行子查询以及如何正确执行笛卡尔积(由CROSS JOIN实现)
SELECT datum,
alldata.worker_id,
reporting_plan.project_id,
SUM(effort::float)/60/60
FROM
(SELECT DISTINCT datum,
reporting_plan.worker_id AS worker_id
FROM
(SELECT datum::date
FROM generate_series('2019-05-01', '2019-12-31', '1 day'::interval) datum) AS dates
CROSS JOIN reporting_plan
ORDER BY datum,
worker_id) AS alldata
LEFT OUTER JOIN reporting_plan ON alldata.worker_id = reporting_plan.worker_id
AND datum <= reporting_plan.end
AND datum >= reporting_plan.start
GROUP BY datum,
alldata.worker_id,
reporting_plan.worker_id,
reporting_plan.project_id
ORDER BY datum,
alldata.worker_id,
reporting_plan.worker_id,
reporting_plan.project_id
预期结果是一个列表,其中包含时间范围内的所有日期以及所有工人和匹配的计划信息(项目和工作量)。
谢谢!
编辑:
基于@jimjimjim的反馈,我设法删除了CROSS JOIN,同时获得了相同的结果:
SELECT datum::date,
alldata.worker_id,
reporting_plan.project_id,
SUM(effort::float)/60/60
FROM
(SELECT DISTINCT generate_series ('2019-05-01', '2019-12-31', '1 day'::interval) AS datum,
worker_id
FROM reporting_plan
ORDER BY datum,
worker_id) AS alldata
LEFT OUTER JOIN reporting_plan ON alldata.worker_id = reporting_plan.worker_id
AND datum <= reporting_plan.end
AND datum >= reporting_plan.start
GROUP BY datum,
alldata.worker_id,
reporting_plan.worker_id,
reporting_plan.project_id
ORDER BY datum,
alldata.worker_id,
reporting_plan.project_id
这里你的问题与Reddit有点不同,用这种方法你将进行原始查询但返回ORM对象。我会做以下事情:
class WorkerEffort(models.Model):
date = models.DateField(...)
worker = models.ForeignKey(Worker, db_column="worker_id")
project = models.ForeignKey(Project, db_column="project_id")
effort = models.DecimalField()
class Meta:
managed = False
管理信息:https://docs.djangoproject.com/en/2.2/ref/models/options/#managed
WorkerEffort.objects.raw('''
SELECT datum,
alldata.worker_id,
reporting_plan.project_id,
SUM(effort::float)/60/60
FROM
(SELECT DISTINCT datum,
worker_id
FROM
(select *, generate_series(start, end, '1 day'::interval) as datum from reporting_plan)
) AS alldata
LEFT OUTER JOIN reporting_plan ON alldata.worker_id = reporting_plan.worker_id
GROUP BY datum,
alldata.worker_id,
reporting_plan.worker_id,
reporting_plan.project_id
ORDER BY datum,
alldata.worker_id,
reporting_plan.worker_id,
reporting_plan.project_id
''')
使用原始查询,您将能够通过WorkerEffort(查询模型)将ID与ORM对象进行匹配。
这会给你相同的结果吗?它消除了交叉连接,这使得使用ORM更容易重写,并且由于系列是使用reporting_plan.start
和end
生成的,因此您不需要在连接条件中包含它们。如果查询中给出的日期需要参数化,则可以将它们作为参数包含在ORM命令中,而不是查询本身。
SELECT datum,
alldata.worker_id,
reporting_plan.project_id,
SUM(effort::float)/60/60
FROM
(SELECT DISTINCT datum,
worker_id
FROM
(select *, generate_series(start, end, '1 day'::interval) as datum from reporting_plan)
) AS alldata
LEFT OUTER JOIN reporting_plan ON alldata.worker_id = reporting_plan.worker_id
GROUP BY datum,
alldata.worker_id,
reporting_plan.worker_id,
reporting_plan.project_id
ORDER BY datum,
alldata.worker_id,
reporting_plan.worker_id,
reporting_plan.project_id