首页 > 解决方案 > Laravel Group 和 Sum hasMany 关系

问题描述

我有一个users包含一列country和用户belongsToMany Categories的表。用户还hasManyPayments表建立关系。

我在尝试着:

  1. 按国家/地区对用户进行分组,显示每个国家/地区最受欢迎的类别(已解决)
  2. 为每个分组的国家/地区汇总amount表中的列payments

每次我尝试加入payments表格时,它都会返回多个结果,这使得总和完全错误。我相信我没有使用正确的查询。

以下是表结构:

用户

id | name  | country

1  | UserA | Canada
2  | UserB | USA
3  | UserC | Canada

类别

id | Name
1  | Housing
2  | Cooking

类别用户

id  | category_id | user_id
1   | 1           | 1
2   | 2           | 2
3   | 1           | 3

付款

id | amount | user_id
1  | 500    | 1
2  | 200    | 2
3  | 150    | 1
4  | 100    | 3

第一个问题已使用以下代码解决:

return User::leftJoin('category_user as cu', 'users.id', '=', 'cu.user_id')
        ->join('categories as c', 'cu.category_id', '=', 'c.id')
        ->groupBy(['country', 'c.name'])
        ->get([
            'users.country',
            'c.name',
            DB::raw('count(*) as total')
        ])
        ->groupBy('country')
        ->values()
        ->map(function (Collection $elt) {
            return $elt->sortByDesc('total')->first();
        });

结果是这样的:

[
  {
    "country": "Canada",
    "name": "Housing",
    "total": 2
  },
  {
    "country": "USA",
    "name": "Cooking",
    "total": 1
  }
]

我想从付款中获取 SUM(金额)作为 total_payments。任何帮助,将不胜感激。

谢谢。

标签: phpmysqllaravel

解决方案


我找不到最小化查询数量的方法,但在我的本地测试中进行了以下工作。

public function foobar()
{
    $popular = User::leftJoin('category_user as cu', 'users.id', '=', 'cu.user_id')
        ->join('categories as c', 'cu.category_id', '=', 'c.id')
        ->groupBy(['country', 'c.name'])
        ->get([
            'users.country',
            'c.name',
            DB::raw('count(*) as total')
        ])
        ->groupBy('country')
        ->values()
        ->map(function (Collection $elt) {
            return $elt->sortByDesc('total')->first();
        }); // this one is same (to get popular category)

    // this one for payments and number of users from that country
    return User::leftJoin('payments as p', 'users.id', '=', 'p.user_id')
        ->groupBy('country')
        ->get(['country', DB::raw('sum(p.amount) as total'), DB::raw('count(distinct(users.id)) as userCount')])
        ->map(function ($col) use ($popular) { // merging two collections into one
            $col->name = $popular->where('country', $col->country)->first()->name;

            return $col;
        });
}

它打印出这样的东西;

[
  {
    "country": "Canada",
    "total": "1150",
    "userCount": 2,
    "name": "Housing"
  },
  {
    "country": "Italy",
    "total": "100",
    "userCount": 1,
    "name": "Kitchen"
  },
  {
    "country": "USA",
    "total": "200",
    "userCount": 1,
    "name": "Cooking"
  }
]

推荐阅读