我想通过过滤表的列(关联表的列上的 OR )来查找行。我可以使用AND版本,但是我不确定如何将->where()
和->matching()
之间的条件更改为OR。
在此示例中,我想通过用户名或常规名称查找用户。在这种情况下,用户hasMany
命名。
$users = $this->Users->find()
->where(['username LIKE' => '%' . $search_term . '%'])
->matching('Names', function($q) use ($search_term){
return $q->where(function($exp, $query) use ($search_term) {
$full_name = $query->func()->concat([
'first' => 'identifier', ' ',
'last' => 'identifier'
]);
return $exp->like($full_name, '%' . $search_term . '%');
});
})
->contain(['Names'])
->limit(10)
->all();
答案 0 :(得分:1)
matching()
creates INNER
joins,并在联接的ON
子句中应用了条件,如果不存在匹配的名称,则会导致用户被过滤掉,因此您不能使用它来创建满足以下条件的OR
条件:您正在寻找。
例如,您可以将名称检查移到相关的子查询(引用外部查询列的查询)和use it with EXISTS
中,如下所示:
$namesMatcher = $this->Users->Names
->find()
->select(['Names.id'])
->where(function($exp, $query) use ($search_term) {
$full_name = $query->func()->concat([
'Names.first' => 'identifier', ' ',
'Names.last' => 'identifier'
]);
return $exp
->equalFields('Names.user_id', 'Users.id')
->like($full_name, '%' . $search_term . '%');
});
$users = $this->Users->find()
->where(function($exp, $query) use ($search_term, $namesMatcher) {
return $exp
->or_(['Users.username LIKE' => '%' . $search_term . '%'])
->exists($namesMatcher);
})
->contain(['Names'])
->limit(10)
->all();
生成的查询如下所示:
SELECT
Users.id ...
FROM
users Users
WHERE
Users.username LIKE '%term%' OR
EXISTS(
SELECT
Names.id
FROM
names Names
WHERE
Names.user_id = Users.id AND
CONCAT(Names.first, ' ', Names.last) LIKE '%term%'
)
例如,也可以使用LEFT
连接来解决此问题,以使用户记录不受连接影响(请参阅Query::leftJoinWith()
),从而允许您创建{{1} }条件,但是由于您似乎不需要进一步访问查询中的名称,因此选择它们实际上没有意义。