2012-09-26 3 views
2

Doctrine의 쿼리 작성기 (Doctrine 2.2를 사용하고 있습니다)를 사용하여 매우 복잡한 쿼리를 작성하려고합니다. 이 모델에서는 Distributor 클래스와 일대 다 관계가있는 DistributorVisit 클래스가 있습니다. 담당자가 대리점을 방문 할 때마다 방문일이있는 DistributorVisit 테이블에 새로운 행이 추가됩니다. 두 테이블의 ER 다이어그램은 here입니다.Doctrine Query Builder, "between"식과 하위 쿼리

이제의 으로 디스트리뷰터를 필터링하고 싶습니다. 따라서 사용자는 날짜 범위 (마지막 방문 및 마지막 방문)를 입력하고 마지막 방문 날짜가이 두 날짜 사이에있는 배포자가 나열됩니다. Doctrine의 Query Builder를 사용하고 있는데 필터에 다른 많은 조건부 쿼리가 있기 때문에이 시나리오에서 객체 지향 접근 방식이 가장 잘 작동하는 것으로 나타났습니다. 여기에 내가 DistributorRepository 수업 시간에 무슨 짓을했는지 :

$qb = $this->getEntityManager()->createQueryBuilder() 
    ->select('o') 
    ->from('MyBundle:Distributor', 'o'); 

// Lots of 'andWhere's here 

$qbv = $this->getEntityManager()->createQueryBuilder(); 

$qb->andWhere($qb->expr()->between(

    $qbv->select($qbv->expr()->max('v.visitDate')) 
     ->from('MyBundle:DistributorVisit', 'v') 
     ->join('MyBundle:Distributor', 'o2', 
      Join::WITH, 
      $qbv->expr()->andX(
       $qbv->expr()->eq('o2.id', 'v.distributorId'), 
       $qbv->expr()->eq('o2.id', 'o.id') 
      )) 
     ->getDQL(), 

    $filter->getLastVisitFrom()->getTimestamp(), 
    $filter->getLastVisitTo()->getTimestamp() 
)); 

이 나에게 다음과 같은 오류 제공 : 그러나, 나는 내 하위 선택이 어디 쿼리 작성기는 문자를 기대하기 때문입니다 추측

[Syntax Error] line 0, col 83: Error: Expected Literal, got 'SELECT' 

을, 하위 쿼리의 결과는 리터럴이어야합니다. 맞습니까? 쿼리 작성기가 그에 따라 괄호를 추가하지 않았기 때문일 수 있습니까?

도움을 주셔서 감사합니다.

SELECT .. 
FROM .. 
WHERE SELECT .. FROM .. BETWEEN .. AND .. 

그러나 다음과 같아야합니다 :

+0

생성 된 쿼리를 참조하는 방법에 대한 자세한 내용은이 게시물을 참조하십시오. 거기서, 당신이 그것을 알아 내지 못했다면, 여기에 질문을 게시하여 우리가 당신을도 더 쉬워지게하십시오! :-) http://stackoverflow.com/questions/7329288/how-do-you-view-a-dql-query-prepared-query-at-runtime – mbinette

답변

3

지금이 문제를 다음과 같은 방법으로 해결 :

$qb = $this->getEntityManager()->createQueryBuilder() 
    ->select('o') 
    ->from('MyBundle:Distributor', 'o'); 

$qbdv = $this->getEntityManager()->createQueryBuilder(); 
$qbdv->select('MAX(dv2.visitDate)') 
    ->from('MyBundle:DistributorVisit', 'dv2') 
    ->where($qbdv->expr()->eq('dv2.distributor', 'o')); 

$maxVisitDate = '('.$qbdv->getDQL().')'; 

$qb->leftJoin(
    'o.distributorVisits', 
    'dv', 
    Join::WITH, 
    $qb->expr()->eq('dv.visitDate', $maxVisitDate) 
); 

$qb->andWhere(
    $qb->expr()->between(
     'dv.visitDate', 
     ':dateFrom', 
     ':dateTo' 
    ) 
) 
->setParameter('dateFrom', $filter->getLastVisitFrom()) 
->setParameter('dateTo', $filter->getLastVisitTo()); 

그래서 기본적으로 다음과 같습니다. DistributorVisit 테이블과 최대 방문 날짜가 Distributor 인 테이블을 결합했습니다. 그 트릭은 (서브 쿼리) ($qb1->getDQL())의 DQL을 Doctrine 식 ($qb2->expr()->eq('column', $qb1->getDQL())에 직접 전달할 수 있다는 사실입니다. 위의 코드에서 왼쪽 조인으로이 작업을 수행했습니다.

1

나는 현재 DQL이 같다고 생각

SELECT .. 
FROM .. 
WHERE (SELECT .. FROM ..) BETWEEN .. AND .. 

난 그냥 괄호 안에 서브 쿼리의 DQL을 넣어 것, 코드를 수정하려면 :

$subQueryDQL = $qbv->select($qbv->expr()->max('v.visitDate')) 
    ->from('MyBundle:DistributorVisit', 'v') 
    ... 
    ->getDQL(); 

$qb->andWhere($qb->expr()->between(
    sprintf('(%s)', $subQueryDQL), 
    $filter->getLastVisitFrom()->getTimestamp(), 
    $filter->getLastVisitTo()->getTimestamp() 
)); 
+0

나는 실제로 당신에게 해결책을 시도하지는 않았지만, 확실히 간다. 올바른 방향으로 아래에서 내가 실제로 그것을 어떻게 풀어 냈는지 알 수 있습니다. 나는 두 가지 해결책이 기본적으로 동일하다고 믿습니다. – thomaskonrad

0

내 경우 :

$qb->andWhere(
"t.field BETWEEN (
    {$subQuerybuilder1->getDQL()} 
) AND (
    {$subQuerybuilder2->getDQL()} 
) 
"); 

당함 :

SELECT ... WHERE t.field BETWEEN (
     SELECT t1.field FROM t1 
    ) AND (
     SELECT t2.field FROM t2 
    ) 
관련 문제