使用聚合结果筛选查询

时间:2012-07-12 20:38:30

标签: sql django aggregate-functions

在Django应用程序中,我有四个模型 - “Proposal”,“ProposalRevision”,“Opinion”和“User”。以下是简化的定义:

class User(models.Model):
    pass

class Proposal(models.Model):
    pass

class ProposalRevision(models.Model):
    proposal = models.ForeignKey(Proposal)
    created = models.DateTimeField()

class Opinion(models.Model):
    user = models.ForeignKey(User)
    proposal = models.ForeignKey(Proposal)
    created = models.DateTimeField()

每个提案可能有很多修订;并且用户可能对给定提议有很多意见。我想提出的问题是:

  

检索给定用户未发表意见的所有提案   自上次提案修订版创建以来。

应用程序用例是我想向用户显示他们发表意见所需的提案。

天真地,我想以这种方式进行查询:

Proposal.objects.annotate(
        latest_revision=Max('proposalrevision__created')
    ).exclude(
        opinion__user=user,
        opinion__created__lte=F('latest_revision')
    )

但是,这不起作用,因为F expressions不支持聚合(yet)。

为了使用“extra”查询来解决这个问题,我开始尝试编写可以执行我想要的查询的vanilla SQL,但是我仍然坚持在'where'子句中使用聚合。我正在使用的SQL看起来像这样:

SELECT ...snip..., MAX("proposal_proposalrevision"."created") as "latest_revision"
FROM "proposal_proposal"
LEFT OUTER JOIN "proposal_proposalrevision" ON
    ("proposal_proposal"."id" = "proposal_proposalrevision"."proposal_id")
WHERE "proposal_proposal"."id" NOT IN (
    SELECT (U1."proposal_id") FROM "proposal_opinion" U1
    WHERE (
        U1."user_id" = 1 AND U1."proposal_id" IS NOT NULL AND
        U1."created" > "latest_proposal"
    )
)
GROUP BY ...snip...

SQLite给我错误“misuse of aggregate: MAX()”。这样可以判断我是使用变量名“latest_proposal”,还是将其替换为聚合函数MAX("proposal_proposalrevision"."created")的重复。

我如何构建此查询以使用聚合过滤返回的集?

1 个答案:

答案 0 :(得分:1)

试试这个解决方案:

SELECT a.*, b.maxrevisiondate AS latest_revision
FROM proposal_proposal a
LEFT JOIN
(
    SELECT proposal_id, MAX(created) AS maxrevisiondate
    FROM proposal_proposalrevision
    GROUP BY proposal_id
) b ON a.id = b.proposal_id
LEFT JOIN proposal_opinion c ON
    a.id = c.proposal_id AND
    (b.maxrevisiondate IS NULL OR c.created > b.maxrevisiondate) AND
    c.user_id = <user_id here>
WHERE c.proposal_id IS NULL