Doctrine的左连接行为与普通的sql

时间:2017-10-13 14:26:27

标签: mysql symfony doctrine left-join dql

我有这个symfony应用程序,其中包含一个问题表和一个与每个问题相关的答案(结果)表:

问题表:

id | question_title
-------------------
1  | Name?
2  | Age?

结果表:

id | answer_text | question_id | user_id
----------------------------------------
1  | John        | 1           | 10
2  | Peter       | 1           | 11
3  | 24          | 2           | 10

用户可以跳过问题,因此它可能不是答案表中给定问题的匹配答案。但是当我检索给定用户的结果时,我想要一个关于每个问题和相关答案的综合列表,或者如果它不存在则需要null。所以(在简单的SQL中)我离开了这样的连接:

 SELECT question_text, answer_text FROM `question` left join result on question.id = result.question_id and user_id=10

得到我:

question_text | answer_text
----------------------------------------
Name?         | John
Age?          | 24 

对于user_id 11,它看起来像:

question_text | answer_text
----------------------------------------
Name?         | Peter
Age?          | null 

正是我的期望。

当我尝试将此查询转换为dql查询时出现问题。我是这样做的:

    $qb->select('q.question_title, r.answer_text');
    $qb->from('AppBundle:Question', 'q');
    $qb->leftJoin(
        'AppBundle:Result',
        'r',
        \Doctrine\ORM\Query\Expr\Join::WITH,
        'q.id = r.question'
    );
    $qb->where('r.user = '.$user->getId());

    $answer= $qb->getQuery()->getResult();

对于在联接右侧具有匹配数据的数据集,它可以正常工作。但是当右侧为null时,它会从返回的数组中被删除但是getResult。这将是普通SQL中上面第一个示例的转储:

array:2 [
    0 => array:2 [
        "question_title" => Name?
        "answer_text" => "John"
    ]
    1 => array:2 [
        "question_title" => Age?
        "answer_text" => "24"
    ]
]

这是第二个例子的转储。没有匹配的答案,我只得到一个1元素的数组:

array:2 [
    0 => array:2 [
        "question_title" => Name?
        "answer_text" => "Peter"
    ]
]

我不知道是否有办法模仿我在普通sql中使用左连接获得的确切行为。

顺便说一句,我使用的数据库引擎是mysql,以防万一有所不同。

编辑:实际上并不是Doctrine2 LEFT JOIN with 2 conditions中提出的问题。以为我在DQL和SQL中有相同的查询行为。原来我只是搞砸了翻译。

1 个答案:

答案 0 :(得分:1)

如果您看到DQL查询,您正在尝试对联接的结果集应用WHERE子句,那么您的过滤器可以正常工作并过滤掉用户ID不是11的结果。

现在,如果你查看你的SQL查询,你没有使用WHERE子句,你试图加入带有问题id的结果表,用户是11,所以它将从结果表中加入用户id为11的行和为非匹配行生成null。

ON子句和WHERE上的过滤器存在差异,ON子句上的过滤器仅在加入时有效,而WHERE应用于加入时结果集(执行连接操作后)。

要编写与SQL等效的DQL,可以将其写为

SELECT q.question_title, r.answer_text
FROM AppBundle:Question q
LEFT JOIN AppBundle:Result r 
     WITH q.id = r.question AND r.user = :user

最好在您的实体中定义映射,而不是手动执行连接Association Mapping