雄辩;获取不在其他表中的行

时间:2017-09-27 07:44:47

标签: eloquent

我正在尝试从表中获取记录列表,其中PK不在复合表中。如果你看到下面的表格,我试图得到candidates以外的所有pool,所以在这种情况下,我应该只获得Eric

+-------------+     +-------------+
| candidates  |     | pools       |
+-------------+     +-------------+
| id | name   |     | id | name   |
+----+--------|     +----+--------|
|  1 | John   |     |  1 | Pool A |
|  2 | Richard|     |  2 | Pool B |
|  3 | Eric   |     |  3 | Pool C | 
+----+--------+     +----+--------+

+--------------------------+
| candidate_pools          |
+--------------------------+
| pool_id | candidate_id   |
+---------+----------------|
|  1      | 1              |
|  1      | 2              |
|  3      | 2              |
|  2      | 1              |
+---------+----------------+

我找到了这个答案:https://laracasts.com/discuss/channels/eloquent/get-records-collection-if-not-exists-in-another-table

$crashedCarIds = CrashedCar::pluck('car_id')->all();
$cars = Car::whereNotIn('id', $crashedCarIds)->select(...)->get();

哪个应该有效,但是在我们相当大且快速增长的数据库中,在一个经常被很多人访问的页面上看起来效率极低。

在普通的MySQL中你会做这样的事情:

WHERE candidates.id NOT IN
( SELECT candidate_id
           FROM candidate_pools
      LEFT JOIN pools
             ON candidate_pools.pool_id = pool.id
)

注意:这些表只是一个简单的说明,但实际的数据库设置和查询要大得多。

1 个答案:

答案 0 :(得分:0)

我设法使用范围,如下所示:

public function scopeNotInPool($query) {

    $query->whereNotIn('candidate_id', function ($query) {
        $query->select('candidate_id')
              ->from('candidate_pool')
              ->join('pool', function ($join) {
                    $join->on('pool.id', '=', 'candidate_pool.pool_id');
                }
            )

        ;
    });

    return $query;

}

然后称之为:

$candidates = Models\Candidate::notInPool()->get();