2013-06-11 104 views
4

我試圖將此SQL轉換爲DQL或任何查詢生成器變體的樣子。Symfony2:WHERE子句中的學說子查詢包括LIMIT

select * 
    from project_release r 
where (select s.title as status_name 
      from release_status_log l 
      left join release_status s 
      on l.release_status_id = s.id 
     where l.release_id = r.id 
     order by l.created_at desc 
     limit 1 
     ) not in ('Complete', 'Closed') 
; 

從爲Release實體倉庫類中,我已經試過這

return $this->getEntityManager()->createQuery(" 
    select r.* 
     from MyBundle:Release r 
    where (select s.title 
       from MyBundle:ReleaseStatusLog l 
       join l.status s 
      where l.release = r 
      order by l.createdAt desc 
      limit 1 
      ) IN ('Complete','Closed') 
    order by r.release_date ASC 
    limit 10 
")->getArrayResult(); 

這給錯誤

[Syntax Error] line 0, col 265: Error: Expected Doctrine\ORM\Query\Lexer::T_CLOSE_PARENTHESIS, got 'limit'

這是指limit 1子查詢。

於是我嘗試這樣做

return $this 
    ->createQueryBuilder('r') 
    ->select('r.*') 
    ->where("(select s.title 
       from MyBundle:ReleaseStatusLog l 
       join l.status s 
      where l.release = r 
      order by l.created_at desc 
      limit 1 
      ) $inClause ('Complete', 'Closed') 
    ") 
    ->setMaxResults($limit) 
    ->orderBy('release_date', 'ASC') 
    ->getQuery() 
    ->getArrayResult() 
; 

其中給出了同樣的錯誤。如何在父查詢中執行每行限制爲1行的子查詢?

  • Symfony的2.0.15
  • 主義2.1.7
  • PHP 5.3.3
  • MySQL的52年5月1日

回答

1

我現在有一個解決方案。最後,我回到了本地查詢系統,並在問題中使用來自實體的結果集映射。

這不是一個好的解決方案,但它的工作原理,直到我看到另一個解決方案,它是這種類型的WHERE子句的唯一選擇。

這裏就是我的查找方法貌似現在

/** 
* Finds Releases by their current status 
* 
* @param array $statuses  White-list of status names 
* @param boolean $blackList Treat $statuses as a black-list 
* @param integer $limit  Limit the number of results returned 
* @param string $order  Sort order, ASC or DESC 
* 
* @throws \InvalidArgumentException 
* 
* @return array <Release> 
*/ 
public function findByCurrentStatus(array $statuses, $blackList=false, $limit=null, $order='ASC') 
{ 
    if (empty($statuses)) 
    { 
    throw new \InvalidArgumentException("Must provide at least one status"); 
    } 
    $inClause = $blackList ? 'not in' : 'in'; 

    $rsm = new ResultSetMappingBuilder($this->getEntityManager()); 
    $rsm->addRootEntityFromClassMetadata('MyBundle:Release', 'r'); 

    $SQL = " 
    select * 
     from project_release r 
    where (select s.title as status_name 
       from release_status_log l 
       left join release_status s 
       on l.release_status_id = s.id 
      where l.release_id = r.id 
      order by l.created_at desc 
      limit 1 
      ) $inClause ('" . implode("','", $statuses) . "') 
    order by r.release_date $order 
    "; 

    if ($limit) 
    { 
    $SQL .= " limit $limit"; 
    } 

    return $this 
    ->getEntityManager() 
    ->createNativeQuery($SQL, $rsm) 
    ->getResult() 
    ; 
} 

我有點討厭回去構建查詢作爲字符串,但哦。呵呵,對於你的鷹眼來說,$statuses不是來自用戶數據,所以在這裏沒有SQL注入漏洞;)

0

除了你的Native SQL解決方案,你可以在單個存儲庫方法中使用DQL創建兩個查詢。

有些調整可能需要,但你可以試試這個:

public function findCompletedReleases() 
{ 
    $em = $this->getEntityManager(); 

    $dqlSubQuery = <<<SQL 
SELECT 
    s.title status_name 
FROM 
    Acme\MyBundle\Entity\ReleaseStatus s, 
    Acme\MyBundle\Entity\ReleaseStatusLog l, 
    Acme\MyBundle\Entity\Release r 
WHERE 
    l.release = r.id AND 
    l.status = s.id 
ORDER BY l.createdAt DESC 
SQL; 

    $statusName = $em->createQuery($dqlSubQuery) 
     ->setMaxResults(1) 
     ->getSingleScalarResult(); 

    $dql = <<<SQL 
SELECT 
    r 
FROM 
    Acme\MyBundle\Entity\Release r 
WHERE 
    :status_name IN ('Complete','Closed') 
ORDER BY r.release_date ASC 
SQL; 

    $q = $em->createQuery($dql) 
     ->setParameters(array('status_name' => $statusName)) 
     ->setMaxResults(10); 

    return $q->getArrayResult(); 
}