2012-07-12 244 views
1

在Django應用程序中,我有四個模型 - 'Proposal','ProposalRevision','Opinion'和'User'。這裏有簡化的定義:過濾器查詢結果集合

每個提案可能有很多修訂;並且用戶可能對於給定的提案有許多意見。我想提出的查詢是:

檢索自上次提案修訂版創建以來給定用戶未留下意見 的所有提案。

應用程序的用例是我想向用戶顯示他們需要留下意見的建議。

天真,我以爲做查詢是這樣的:

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

嘗試這種解決方案:

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 
+0

謝謝,這是卓有成效的作爲原料查詢。爲了更容易地與ORM進行整合,我決定向ProposalRevision模型中添加一個post_save信號,該模型根據其日期更新了Proposal的所有Opinion模型上的「is_stale」布爾值,從而極大地簡化了查詢。 – user85461 2012-07-13 21:46:01