2016-01-13 68 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