【问题标题】:Counting related rows in a child table计算子表中的相关行
【发布时间】:2023-03-15 01:41:01
【问题描述】:

我一直在尝试使用 eloquent 进行一些查询并计算相关表。

表格:

  • 请求
  • 联系方式(属于请求)
  • 历史(属于联系人)

因此,X 个请求每个都有 Y 个联系人,每个联系人都有 Z 个历史记录

使用 sql 我可以做这样的事情来得到所有的计数。

SELECT
    id,
    (
         SELECT count(contact.id)
         FROM contact 
         WHERE contact.requests_id = requests.id
    ) AS n_contact,
    (
         SELECT count(history.id)
         FROM contact INNER JOIN history ON (history.contact_id = contact.id)
         WHERE contact.requests_id = requests.id
    ) AS n_history
FROM requests;

但是在使用 eloquent 构建查询时我有点迷茫。例如,如果我为给定请求选择所有联系人,我会在什么时候加入/计算历史记录?还是我需要在这 3 个表的相关模型中添加一些访问器?

public function getAllContacts($id) {
    return Requests::where('requests.id', '=', $id)
            ->join('requests', 'contact.requests_id', '=', 'requests.id')
            ->select('contact.*', 'requests.name');
            ->get();
}

提前感谢您的帮助。

【问题讨论】:

  • 您想计算 Z/Y 和 Y/X、Z/X 还是什么?
  • 我想计算每个 X 的所有 Z,以及每个 Y 的所有 Z。所以给定一个特定的 Z 或 X,我可以计算 Y。

标签: php mysql sql laravel eloquent


【解决方案1】:

/* 在请求模型中建立关系 */

public function contacts()
{
    return $this->hasMany('App\Model\Contact', 'request_id', 'id');
}

/* 使用withCount() 获取联系人总数 */

public function getAllContacts($id) {
    return Requests::with('contacts')
            ->withCount('contacts')
            ->find($id);
}

【讨论】:

    【解决方案2】:

    如果您想使用 Eloquent 而不是手动连接,您可以为此使用辅助关系:

    // Request model
    public function contactsCount()
    {
        return $this->hasOne('Contact')->selectRaw('request_id, count(*) as aggregate')->groupBy('request_id');
    }
    
    public function getContactsCountAttribute()
    {
        if ( ! array_key_exists('contactsCount', $this->relations)) $this->load('contactsCount');
    
        return $this->getRelation('contactsCount')->aggregate;
    }
    

    Contact 模型对History 模型也是如此。

    对于计算远关系(Request -> History),您可以使用hasManyThrough 关系稍作调整。

    通过这种方式,您可以为多个模型急切加载这些聚合,而不会出现 n+1 问题,既简单又方便:

    $requests = Request::with('contactsCount', 'contacts.historyCount')->get();
    // 1 query for reuqests, 1 query for contacts count and 2 queries for contacts.historyCount
    
    // example output
    $requests->first()->contactsCount; // 17
    $requests->first()->contacts->first()->historyCount; // 5
    

    【讨论】:

      猜你喜欢
      • 2011-10-07
      • 1970-01-01
      • 2015-01-23
      • 1970-01-01
      • 1970-01-01
      • 2017-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多