skip to Main Content

I have a reports table which looks like something as follows:

Reports is monthly reports of users putting their efforts. It’s many to many relationship table.

id user_id project_id total_effort created_at
1 5 232 40 2023-01-23

I want to get all users with their contributions projects-wise so that I can create an excel something like this.

enter image description here

I am able to group users by group and get their collective data, but unable to group by project id as well.

So far here is my query

  $data = Report::select('user_id')
            ->selectRaw("SUM(total_effort) as total, DATE_FORMAT(report_for_date, '%b,%Y') new_date")
            ->groupBy('user_id')->with('userDetail:id,first_name,last_name')->get();

And this query return

 [0] => Array
        (
            [user_id] => 2
            [total] => 500
            [new_date] => Dec,2022
            [user_detail] => Array
                (
                    [id] => 2
                    [first_name] => Hermione
                    [last_name] => Granger
                )

        )

But what I am actually looking for is something like this:

[0] => Array
        (
            [user_id] => 2
            [total] => 500
            [new_date] => Dec,2022
            [projects]=>Array(
                [0]=>Array(
                    [project_id]=>1,
                    [total]=>30,
                    [project_detail]=>Array(
                            [id]=>1
                            [name]=>Project 1
                    )
                )
                [1]=>Array(
                   [project_id]=>41,
                    [total]=>30,
                    [project_detail]=>Array(
                            [id]=>41
                            [name]=>Project 41
                    )
                )
                [2]=>Array(
                    [project_id]=>32,
                    [total]=>30,
                    [project_detail]=>Array(
                            [id]=>32
                            [name]=>Project 32
                    )
                )
            )
            [user_detail] => Array
                (
                    [id] => 2
                    [first_name] => Hermione
                    [last_name] => Granger
                )

        )

So that I can loop the data and plot them in excel.
How can this be done? Even if it is just a Raw MySQL query how to do Groupby inside a groupBy?

Some reference that I checked but without any help

2

Answers


  1. You can use with() method to load the relation with groupby clause

    $data = Report::select('user_id', 'project_id')
        ->selectRaw("SUM(total_effort) as total, DATE_FORMAT(report_for_date, '%b,%Y') new_date")
        ->groupBy('user_id')
        ->groupBy('project_id')
        ->with('userDetail:id,first_name,last_name')
        ->with('projectDetail:id,name')
        ->get();
    
    Login or Signup to reply.
  2. I would query the active projects within the reporting period and then use that to build up the main query with conditional aggregation (pivot) –

    // get list of projects within reporting period
    $projects = DB::table('projects p')
        ->join('reports r', 'p.id', '=', 'r.project_id')
        ->select('p.id', 'p.name')
        ->whereBetween('r.created_at', ['2023-01-01', '2023-01-31'])
        ->groupBy('p.id')
        ->get();
    
    // build conditional aggregates
    $columns = ['CONCAT(u.first_name, ' ', u.last_name) AS username'];
    
    foreach ($projects as $project) {
        $columns[] = "SUM(IF(r.project_id = {$project->id}, total_effort, 0)) AS project_{$project->id}";
    }
    
    // Add total column
    $columns[] = 'SUM(total_effort) AS total';
    
    $report = DB::table('reports r')
        ->join('users u', 'r.user_id', '=', 'u.id')
        ->selectRaw(implode(',', $columns))
        ->whereBetween('r.created_at', ['2023-01-01', '2023-01-31'])
        ->groupBy('r.user_id')
        ->get();
    

    The idea is to build and execute a query which looks something like this –

    SELECT
        CONCAT(u.first_name, ' ', u.last_name) AS username,
        SUM(IF(r.project_id = 232, total_effort, 0)) AS project_232,
        SUM(IF(r.project_id = 233, total_effort, 0)) AS project_233,
        SUM(IF(r.project_id = 234, total_effort, 0)) AS project_234,
        SUM(total_effort) AS total
    FROM reports r
    JOIN users u ON r.user_id = u.id
    WHERE r.created_at BETWEEN '2023-01-01' AND '2023-01-31'
    GROUP BY r.user_id
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search