2016-01-13 119 views
5

我正在重构一个Zend框架应用程序使用原则2.5 DBAL而不是Zend_DB(ZF1)。我有以下Zend_Db的查询:加入子查询与教条2 DBAL

$subSelect = $db->select() 
    ->from('user_survey_status_entries', array('userSurveyID', 'timestamp' => 'MIN(timestamp)')) 
    ->where('status = ?', UserSurveyStatus::ACCESSED) 
    ->group('userSurveyID'); 


$select = $db->select() 
    // $selectColNames contains columns both from the main query and 
    // the subquery (e.g. firstAccess.timestamp AS dateFirstAccess). 
    ->from(array('us' => 'user_surveys'), $selectColNames) 
    ->joinLeft(array('firstAccess' => $subSelect), 'us.userSurveyID = firstAccess.userSurveyID', array()) 
    ->where('us.surveyID = ?', $surveyID); 

这将导致以下MySQL查询:

SELECT `us`.`userSurveyID`, 
    // More columns from main query `us` 
    `firstAccess`.`timestamp` AS `dateFirstAccess` 
FROM `user_surveys` AS `us` 
LEFT JOIN (
    SELECT `user_survey_status_entries`.`userSurveyID`, 
      MIN(timestamp) AS `timestamp` 
    FROM `user_survey_status_entries` 
    WHERE (status = 20) 
    GROUP BY `userSurveyID` 
) AS `firstAccess` ON us.userSurveyID = firstAccess.userSurveyID 
WHERE (us.surveyID = '10') 

我无法弄清楚如何使用学说2.5查询生成器加入子查询。在主查询中,我需要从子查询中选择列。我已阅读here该原则不支持连接子查询。如果这仍然是真的,我可以使用doctrine DBAL的SQL查询构建器以另一种方式编写此查询吗?原生SQL可能对我而言不是一个好的解决方案,因为此查询将在代码中稍后动态扩展。

+2

检索您的subSelect的结果,然后将其用作您选择的参数。 – Veve

+0

@Veve subSelect的结果将是一个包含数千个元素的数组,我认为它不是首先检索它并将其用作主查询中的参数的可行方法。 – aimfeld

+0

这是您试图构建的DQL或SQL吗? – Ocramius

回答

7

我已经适应这个DQL example到DBAL找到了解决办法。诀窍是获取子查询的原始SQL,将其包装在括号中,并加入它。子查询中使用的参数必须在主查询中设置:

$subSelect = $connection->createQueryBuilder() 
    ->select(array('userSurveyID', 'MIN(timestamp) timestamp')) 
    ->from('user_survey_status_entries') 
    // Instead of setting the parameter in the main query below, it could be quoted here: 
    // ->where('status = ' . $connection->quote(UserSurveyStatus::ACCESSED)) 
    ->where('status = :status') 
    ->groupBy('userSurveyID'); 

$select = $connection->createQueryBuilder() 
    ->select($selectColNames) 
    ->from('user_surveys', 'us') 
    // Get raw subquery SQL and wrap in brackets. 
    ->leftJoin('us', sprintf('(%s)', $subSelect->getSQL()), 'firstAccess', 'us.userSurveyID = firstAccess.userSurveyID') 
    // Parameter used in subquery must be set in main query. 
    ->setParameter('status', UserSurveyStatus::ACCESSED) 
    ->where('us.surveyID = :surveyID')->setParameter('surveyID', $surveyID); 
+2

我认为这行有一个错误: ' - > leftJoin('us',sprintf('(%s)',$ subSelect-> getSQL()),'firstAccess','us.userSurveyID = firstAccess.userSurveyID') 第三个参数必须是'Expr \ Join: :ON'或'Expr \ Join :: WITH.' – Tsounabe

+1

'Expr \ Join:ON'和'Expr \ Join :: WITH'只适用于'ORM'命名空间的QueryBuilder。例如'\ Doctrine \ ORM \ Query \ Expr \ Join'用于'\ Doctrine \ ORM \ QueryBuilder :: join'独立的'DBAL'没有'Join'对象。 'DBAL'连接隐含地总是一个'ON'条件。请参阅:http://www.doctrine-project.org/api/dbal/2.5/class-Doctrine.DBAL.Query.QueryBuilder.html#_join vs http://www.doctrine-project.org/api/orm/ 2.5/class-Doctrine.ORM.QueryBuilder.html#_join – fyrye

+0

不起作用,请参考https://stackoverflow.com/questions/24600439/error-in-nested-subquery-in-dql-class-is-not-定义 –

3

要回答你的问题,这部分:

我无法弄清楚如何使用学说2.5查询生成器

加入子查询可以使2查询构建器实例和使用第一个查询的子句中的第二个DQL。举个例子:

->where($qb->expr()->notIn('u.id', $qb2->getDQL()) 

检查例子hereherefind more using Google

+0

这可能适用于where子句中的子查询,但我需要从子查询中选择主查询中的列。 – aimfeld

+0

@aimfeld你可以通过设置'u1'和'u2'来做到这一点(与你的主要查询绑定),然后执行'andWhere('u1.id = u2.id');'。 – Wilt

+0

我已经用最终的mysql查询更新了描述。如果你可以给出一个代码示例来实现这个查询(我没有明白你的意思,对不起),这将是非常有帮助的。 – aimfeld