# 模型的关联查询

```php

class User extends Model
{
    protected $table = 'user';
    // 一对多关联 Book 表
    public function books()
    {
        return $this->hasMany(Book::class, 'user_id', 'id');
    }
}


class Book extends Model
{
    protected $table = 'book';

    // 反向关联
    public function user()
    {
        return $this->belongsTo(User::class, 'user_id', 'id');
    }
}

```

查询

```php
//下面两种查询是一样的;
$books = User::find(1)->books;

$books = User::find(19)->book()->get();
```

```sql
select * from `user` where `user`.`id` = ? limit 1

select * from `book` where `book`.`user_id` = ? and `book`.`user_id` is not null
```

```php
//可以采用 where 筛选或闭包 
$books = User::find(1)
    ->books()
    ->where('id', 1)
    ->orWhere('id', 11)
    ->get();
```
```sql
select * from `user` where `user`.`id` = ? limit 1

select * from `book` where `book`.`user_id` = ? and `book`.`user_id` is not null and `id` = ? or `id` = ?
```

```php
$books = User::find(1)
    ->books()
    ->where(function ($query) { 
        $query->where('id', 1)->orWhere('id', 11);
    })->get();
```

```sql
select * from `user` where `user`.`id` = ? limit 1

select * from `book` where `book`.`user_id` = ? and `book`.`user_id` is not null and (`id` = ? or `id` = ?)
```

has()方法，可以查询某些条件下的关联查询数据

```php
// 获取存在关联书籍的用户列表(言下之意:至少一本书) 
$users = User::has('books')->get();
```
```sql
select * from `user` where exists (
    select * from `book` where `user`.`id` = `book`.`user_id`
)
```

```php
// 获取存在关联书籍(并超过 3 条)的用户列表 
$users = User::has('book','>=', 3)->get(); 
```

```sql
select * from `user` where (
    select count(*) from `book` where `user`.`id` = `book`.`user_id`
) >= 3
```

使用whereHas()方法，创建闭包查询

```php
//whereHas 闭包用法
$users = User::whereHas('books', function ($query) {
        //这里$query 是 book 表，通过 user_id 查询，返回 user 表数据
        $query->where('user_id', 19); 
    })->get();
```
```sql
select * from `user` where exists (
    select * from `book` where `user`.`id` = `book`.`user_id` and `user_id` = ?
)
```

使用doesntHave()方法，即has()的反向操作

```php
// 获取不存在关联书籍的用户列表，闭包用法:whereDoesntHave() 
$users = User::doesntHave('books')->get();
```
```sql
select * from `user` where not exists (
    select * from `book` where `user`.`id` = `book`.`user_id`
)
```

使用withCount()方法，可以进行关联统计

```php
//关联统计，会自动给一个 book_count 字段 //统计每个用户有多少本书
User::withCount('books')->get();
```

```sql
select `user`.*,
(select count(*) from `book` where `user`.`id` = `book`.`user_id`) as `books_count` 
from `user`
```
```php
// 给多个关系添加统计:profile_count，book_count
User::withCount(['profile', 'books'])->get();
```

```sql
select `user`.*, 
(select count(*) from `profile` where `user`.`id` = `profile`.`user_id`) as `profile_count`, 
(select count(*) from `book` where `user`.`id` = `book`.`user_id`) as `books_count` 
from `user`
```

```php
//关联统计再结合闭包进行筛选，还可以设置别名
User::withCount(['profile', 'books' => function ($query) {
        //这里限制被统计的记录
        $query->where('user_id', 19); 
    }])->get();
```

```sql
select `user`.*, 
(select count(*) from `profile` where `user`.`id` = `profile`.`user_id`) as `profile_count`, 
(select count(*) from `book` where `user`.`id` = `book`.`user_id` and `user_id` = ?) as `books_count` 
from `user`
```

https://www.bilibili.com/video/BV1gE411j78F?p=29&spm_id_from=pageDriver&vd_source=efbb4dc944fa761b6e016ce2ca5933da