【问题标题】:Doctrine's left join behaves different than plain sqlDoctrine 的左连接行为与普通 sql 不同
【发布时间】:2017-10-13 14:26:26
【问题描述】:

我有这个 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();

对于在连接右侧具有匹配数据的数据集,它可以正常工作。但是当右侧为空时,它会从返回的数组中删除,但 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 中表现不同。原来我只是把翻译搞砸了。

【问题讨论】:

  • Doctrine2 LEFT JOIN with 2 conditions 的可能重复项这显然是基本的,你在谷歌上发现了什么,比如'doctrine left join multiple on'?
  • 这不是我真正要问的。我以为我在 SQL 中有一个查询在 DQL 中的行为不同,但实际上我翻译错了,正如下面的用户所指出的那样。
  • 在那个问题中 是什么(尽管它的(糟糕的)标题)是为什么在给定一些 joins 和 where 的情况下结果在某种程度上是错误的。因此,对问题的合理描述包括您的情况。在该问题中回答的是,提问者在需要 on 时错误地将条件放入 where。这就是你的问题的答案。这也出现在许多其他热门歌曲中,也出现在变奏曲中。我找到我给出的谷歌答案。所以...
  • 请:1 始终想:这可能是一个问题吗?因为它可能不是。 2 总是在谷歌上搜索许多清晰、简洁和具体(但没有特定于应用程序的名称)的问题/问题/需要的措辞和标签组合并阅读 许多 命中。 3 如果找不到答案,则将 1 google 设为标题。 4 始终提供minimal reproducible example。没有它,应该关闭一个问题(阻止答案),并引发 cmets 进行澄清和“回答”帖子,这些帖子只是猜测,不应该发布。 5 所有这些都在 How to Ask 和其他 help center 链接中,所以请继续阅读。

标签: mysql symfony doctrine left-join dql


【解决方案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

【讨论】:

  • 是的,这很明显,出于某种原因,我一直认为我的原始 SQL 中有一个 where 过滤器。底线:我的错。谢谢。
猜你喜欢
  • 1970-01-01
  • 2018-10-24
  • 1970-01-01
  • 1970-01-01
  • 2021-12-27
  • 1970-01-01
  • 2021-11-28
  • 2021-09-02
  • 1970-01-01
相关资源
最近更新 更多