Doctrine 的左连接行为不同于普通 sql
Doctrine's left join behaves different than plain sql
我有这个 symfony 应用程序,其中有 table 个问题和 table 个与每个问题相关的答案(结果):
问题table:
id | question_title
-------------------
1 | Name?
2 | Age?
结果table:
id | answer_text | question_id | user_id
----------------------------------------
1 | John | 1 | 10
2 | Peter | 1 | 11
3 | 24 | 2 | 10
用户可能会跳过一个问题,因此它可能不是答案 table 中给定问题的匹配答案。但是当我检索给定用户的结果时,我想要一个包含每个问题和相关答案的完整列表,或者为空,以防它不存在。所以(简单地说 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 中表现不同。原来我只是在翻译上搞砸了。
如果您看到 DQL 查询,您正在尝试在连接的结果集上应用 WHERE
子句,以便您的过滤器正常工作并过滤掉用户 ID 不是 11 的结果。
现在,如果您查看 SQL 查询,您没有使用 WHERE
子句,您正在尝试加入结果 table,问题 ID 为 11,因此它将加入来自结果 table 的行,其中用户 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
我有这个 symfony 应用程序,其中有 table 个问题和 table 个与每个问题相关的答案(结果):
问题table:
id | question_title
-------------------
1 | Name?
2 | Age?
结果table:
id | answer_text | question_id | user_id
----------------------------------------
1 | John | 1 | 10
2 | Peter | 1 | 11
3 | 24 | 2 | 10
用户可能会跳过一个问题,因此它可能不是答案 table 中给定问题的匹配答案。但是当我检索给定用户的结果时,我想要一个包含每个问题和相关答案的完整列表,或者为空,以防它不存在。所以(简单地说 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 中表现不同。原来我只是在翻译上搞砸了。
如果您看到 DQL 查询,您正在尝试在连接的结果集上应用 WHERE
子句,以便您的过滤器正常工作并过滤掉用户 ID 不是 11 的结果。
现在,如果您查看 SQL 查询,您没有使用 WHERE
子句,您正在尝试加入结果 table,问题 ID 为 11,因此它将加入来自结果 table 的行,其中用户 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