2013-03-16 4 views
1

Django ORM (다른 검색어의 일부로 QuerySet 만 사용)에서 하위 쿼리를 만드는 것이 간단하지만 하위 쿼리가 "상위"(외부, 기본) 검색어의 입력란을 참조 할 수 있습니까?Django 하위 쿼리에서 "상위"쿼리를 참조 할 수 있습니까?

내가 달성하고자하는 전체 사례는 SQL Fiddle을 참조하십시오. 나는 두 가지 질문 (other one here)으로 나누었다. 이 경우 도달해야하는 값을 나타내는 Whole 모델이 있습니다. 몇몇 Part은 자신의 (계산 된) 값으로 그것에 기여합니다. 이 아니며이 아닌 모든 Whole을 검색하고 싶습니다 (즉, 은 개별 값의 합계와 다릅니다).

select w.* 
    from whole w 
    where w.total_value != (
    select sum(value expression) 
     from part p 
     where p.whole_id = w.id 
     group by p.whole_id 
); 

장고 ORM을 사용하여 어떻게 할 수 있는지 (또는 가능한지) 알 수 없습니다. 나는 __in을 사용하여 서브 쿼리 중 manyexamples을 보았으며 결과가 실제로는 단일 쿼리로 실행되었다는 것을 print qs.query으로 확인할 수 있었지만 두 쿼리가 서로 독립적 인 경우에만 확인할 수있었습니다. 여기서 하위 쿼리는 상위 쿼리 (w.id)의 필드로 제한됩니다. Download 또는 Browse : 나는

는 다음의 경우 사람에 실험 할하는 SSCCE의 ... F(), Q(), 또는 extra를 사용하여 생각하지만, 확실히 무엇을 알아낼 수 없습니다. 위에 연결된 SQL fiddle과 동일한 모델 및 데이터를 가지고 있습니다.


는 업데이트 :

q = Q(part__isnull=True) | ~Q(partial=F('total_value')) 
qs = Whole.objects.annotate(partial=Sum(...)).filter(q).distinct() 

# And if total_value can be zero: 
qs = qs.exclude(part__isnull=True, total_value=0) 

일반적인 경우 : 내 특정 사건에 대한, 난, 난 그냥 group byhaving (this SQL Fiddle으로 표시)를 사용할 수있는 하위 쿼리를 할 필요가 없습니다 발견 subqueries에 대해서는 비록 아직 (일부 원시 SQL을 사용하지 않고, my answer below처럼) 풀리지 않습니다.

답변

2

내가 가장 원시 SQL로 고안이 솔루션은 사용 extrawhere :

  • 먼저 내부 쿼리를 만들;

    qs1 = Part.objects.extra(where=['whole_id = "applabel_whole"."id"'])... 
    

    그런 다음합니다 외부 쿼리에서 하나에 제한 필드를 비교, 사용자 정의 where 구성 요소를 지정하는 extra를 사용, 그것은 같은 (테이블 이름/별칭을 하드 코딩해야하는)가 나타납니다 나머지 작업 (이 경우에는 단일 필드의 그룹화, 집계 및 반환을 위해 valuesannotate을 사용).

  • 나서 또한 extrawhere를 사용하여, 외부 쿼리 (.query 사용) 내부 쿼리 생성 SQL을 포함

    qs = Whole.objects.extra(where=['total_value != ({})'.format(qs1.query)]) 
    

extra 통화의 코드 단편은 휴대하지 않을 수도 (전의.일부 백엔드는 !=을 사용하고 다른 것은 <>을 사용하며 테이블 이름을 인용하는 올바른 방법은 다를 수 있습니다.)하지만 내부 쿼리의 나머지는 (ORM에 의해 생성되었으므로) 이루어져야합니다.

결과 검색어는 내가 찾고있는 항목과 일치합니다 (집계 부분은 the other question에 해당). 가독성을 위해 포맷 된 SQL :

>>> qs1 = Part.objects.extra(
     where=['whole_id = "aggregation_subquery_whole"."id"'] 
    ).values('whole_id').annotate(sum=Sum('before__value')).values('sum') 

>>> qs = Whole.objects.extra(where=['total_value != ({})'.format(qs1.query)]) 

>>> print qs.query 

SELECT "aggregation_subquery_whole"."id", 
     "aggregation_subquery_whole"."total_value" 
FROM "aggregation_subquery_whole" 
WHERE total_value != (
    SELECT SUM("aggregation_subquery_sequence"."value") AS "sum" 
    FROM "aggregation_subquery_part" 
     LEFT OUTER JOIN "aggregation_subquery_sequence" ON 
      ("aggregation_subquery_part"."before_id" = 
      "aggregation_subquery_sequence"."id") 
    WHERE whole_id = "aggregation_subquery_whole"."id" 
    GROUP BY "aggregation_subquery_part"."whole_id" 
) 
관련 문제