代码之家  ›  专栏  ›  技术社区  ›  waspinator

cakephp构建查询以过滤模型或关联模型

  •  0
  • waspinator  · 技术社区  · 6 年前

    我想通过筛选表的列来查找行, 在关联表的列上。我可以得到一个和版本的工作,但我不知道如何改变之间的条件 ->where() ->matching() 对或。

    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();
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   ndm    6 年前

    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%'
        )
    

    这也可以通过使用示例a来解决 LEFT 连接,这样用户记录就不会受到连接的影响(请参阅 Query::leftJoinWith() ),允许您创建 条件,但由于您似乎不需要进一步访问查询中的名称,因此选择它们实际上没有意义。