删除 CakePHP 3 和 belongsToMany 中重复的 find() 结果
Remove duplicate find() Results in CakePHP 3 and belongsToMany
架构
`a`
|id |
|a1 |
`b`
|id |
|b1 |
|b2 |
`c`
|a_id|b_id|some_data|
|a1 |b1 |lorem ipsum|
|a1 |b1 |dolor|
|a1 |b2 |abc|
A belongsToMany B 通过 C
查询
$this->As->find()->contain(['Bs' => function (Query $q) {
return $q->distinct();
}]);
在 CakePHP 3 中执行上述查询将 return A 和三个 B,因为 table 中有三行(b1 两次)。有没有办法使用 query builder 删除重复结果?我试过 distinct() 但没有用。我怀疑是因为_joinData 不同,但我不确定。
没有参数的 distinct()
将应用于所有 selected 列,即它会产生如下内容:
DISTINCT c.a_id, c.b_id, c.some_data, b.id
对所有列应用不同,这将有效地不会删除任何重复项,因为由这些列组成的所有元组都将不同。
您必须仅在特定列上应用不同,以便您的副本之间实际上存在差异,例如使用 Bs.id
:
$q->distinct('Bs.id');
这将创建 DISTINCT ON(Bs.id)
或 GROUP BY Bs.id
,具体取决于您使用的 DBMS。此外,根据您使用的 DBMS 及其配置,GROUP BY
将导致错误,因为查询将 select 不在 GROUP BY
子句中的非聚合列(参见示例 MySQL and the ONLY_FULL_GROUP_BY
mode).
解决这个限制需要一些技巧,我过去使用的一种方法是在联接 table 和 select [=20= 上使用显式中间关联] 数据在一个单独的查询中,中间关联的查询可以安全地应用分组。
你的例子是 As hasMany Cs
和 Cs belongsTo Bs
,然后包含连接 table,你可以在其中应用分组,它看起来像这样:
$this->As
->find()
->contain([
'Cs' => [
'queryBuilder' => function (\Cake\ORM\Query $query) {
return $query
->select(['Cs.a_id', 'Cs.b_id'])
->group(['Cs.a_id', 'Cs.b_id']);
},
'Bs' => [
'strategy' => \Cake\ORM\Association\BelongsTo::STRATEGY_SELECT
]
]
]);
结果的格式当然会有所不同,因此您可能需要重新格式化它以防万一。
架构
`a`
|id |
|a1 |
`b`
|id |
|b1 |
|b2 |
`c`
|a_id|b_id|some_data|
|a1 |b1 |lorem ipsum|
|a1 |b1 |dolor|
|a1 |b2 |abc|
A belongsToMany B 通过 C
查询
$this->As->find()->contain(['Bs' => function (Query $q) {
return $q->distinct();
}]);
在 CakePHP 3 中执行上述查询将 return A 和三个 B,因为 table 中有三行(b1 两次)。有没有办法使用 query builder 删除重复结果?我试过 distinct() 但没有用。我怀疑是因为_joinData 不同,但我不确定。
distinct()
将应用于所有 selected 列,即它会产生如下内容:
DISTINCT c.a_id, c.b_id, c.some_data, b.id
对所有列应用不同,这将有效地不会删除任何重复项,因为由这些列组成的所有元组都将不同。
您必须仅在特定列上应用不同,以便您的副本之间实际上存在差异,例如使用 Bs.id
:
$q->distinct('Bs.id');
这将创建 DISTINCT ON(Bs.id)
或 GROUP BY Bs.id
,具体取决于您使用的 DBMS。此外,根据您使用的 DBMS 及其配置,GROUP BY
将导致错误,因为查询将 select 不在 GROUP BY
子句中的非聚合列(参见示例 MySQL and the ONLY_FULL_GROUP_BY
mode).
解决这个限制需要一些技巧,我过去使用的一种方法是在联接 table 和 select [=20= 上使用显式中间关联] 数据在一个单独的查询中,中间关联的查询可以安全地应用分组。
你的例子是 As hasMany Cs
和 Cs belongsTo Bs
,然后包含连接 table,你可以在其中应用分组,它看起来像这样:
$this->As
->find()
->contain([
'Cs' => [
'queryBuilder' => function (\Cake\ORM\Query $query) {
return $query
->select(['Cs.a_id', 'Cs.b_id'])
->group(['Cs.a_id', 'Cs.b_id']);
},
'Bs' => [
'strategy' => \Cake\ORM\Association\BelongsTo::STRATEGY_SELECT
]
]
]);
结果的格式当然会有所不同,因此您可能需要重新格式化它以防万一。