1

i have four table socket , office , container, project i need to join these table with primey table soket and add count in each table group by socket.id .

$data['socjetsreport'] = DB::table('socket')
    ->limit(5)
    ->join('attached', 'attached.socket_id', '=', 'socket.id', 'left outer')
    ->join('office', 'office.socket_id', '=', 'socket.id', 'left outer')
    ->join('container', 'container.socket_id', '=', 'socket.id', 'left outer')
    ->join('project', 'project.socket_id', '=', 'socket.id', 'left outer')
    ->join('users', 'users.id', '=', 'socket.employee_id', 'left outer')
    ->select('socket.id as id', 'socket.name as name',  'users.name as uname', 
        DB::raw("count(attached.socket_id) as attccount"))
    ->groupBy('socket.id')
    ->get();

I try to apply it in MySQL query and it run well but in laravel it just give me wrong count.

This is my MySQL query:

SELECT
    users.name,
    COUNT(*) AS attached,
    (
        SELECT COUNT(*) FROM socket
        LEFT OUTER JOIN container ON socket.id = container.socket_id
        WHERE socket.id = @id
    ) AS container,
    (
        SELECT COUNT(*) FROM socket
        LEFT OUTER JOIN project ON socket.id = project.socket_id
        WHERE socket.id = @id
    ) AS project, 
    (
        SELECT COUNT(*) FROM socket
        LEFT OUTER JOIN office ON socket.id = office.socket_id
        WHERE socket.id = @id
    ) AS office 
FROM socket
LEFT OUTER JOIN attached ON socket.id = attached.socket_id
LEFT OUTER JOIN users ON socket.employee_id = users.id WHERE socket.id = @id
GROUP BY users.name
IGP
  • 14,160
  • 4
  • 26
  • 43
Ayman osman
  • 13
  • 1
  • 3

2 Answers2

0

Since LEFT OUTER JOIN is the same as LEFT JOIN you could just use the query builder's leftJoin() method.

For all the subqueries in your SELECT statement, you should use the query builder's selectSub() method.

    /**
     * Add a subselect expression to the query.
     *
     * @param  \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder|string  $query
     * @param  string  $as
     * @return $this
     *
     * @throws \InvalidArgumentException
     */
    public function selectSub($query, $as)
    {
        [$query, $bindings] = $this->createSub($query);

        return $this->selectRaw(
            '('.$query.') as '.$this->grammar->wrap($as), $bindings
        );
    }

The resulting query looks like this:

use Illuminate\Database\Query\Builder;

$data['socjetsreport'] = DB::table('socket')
    ->select('users.name')
    ->selectRaw('count(*) as attached')
    ->selectSub(
        function (Builder $query) use ($socketId) {
            return $query->selectRaw('count(*)')->from('socket')
                         ->leftJoin('container', 'socket.id', 'container.socket_id')
                         ->where('socket.id', $socketId);
        },
        'container'
    )
    ->selectSub(
        function (Builder $query) use ($socketId) {
            return $query->selectRaw('count(*)')->from('socket')
                         ->leftJoin('project', 'socket.id', 'project.socket_id')
                         ->where('socket.id', $socketId);
        },
        'project'
    )
    ->selectSub(
        function (Builder $query) use ($socketId) {
            return $query->selectRaw('count(*)')->from('socket')
                         ->leftJoin('office', 'socket.id', 'office.socket_id')
                         ->where('socket.id', $socketId);
        },
        'office'
    )
    ->leftJoin('attached', 'socket.id', 'attached.socket_id')
    ->leftJoin('users', 'socket.employee_id', 'users.id')
    ->where('socket.id', $socketId)
    ->groupBy('users.name')
    ->get();

Or like this if you are hung up on using LEFT OUTER JOIN.

use Illuminate\Database\Query\Builder;

$data['socjetsreport'] = DB::table('socket')
    ->select('users.name')
    ->selectRaw('count(*) as attached')
    ->selectSub(
        function (Builder $query) use ($socketId) {
            return $query->selectRaw('count(*)')->from('socket')
                         ->join('container', 'socket.id', '=', 'container.socket_id', 'left outer')
                         ->where('socket.id', $socketId);
        },
        'container'
    )
    ->selectSub(
        function (Builder $query) use ($socketId) {
            return $query->selectRaw('count(*)')->from('socket')
                         ->join('project', 'socket.id', '=', 'project.socket_id', 'left outer')
                         ->where('socket.id', $socketId);
        },
        'project'
    )
    ->selectSub(
        function (Builder $query) use ($socketId) {
            return $query->selectRaw('count(*)')->from('socket')
                         ->join('office', 'socket.id', '=', 'office.socket_id', 'left outer')
                         ->where('socket.id', $socketId);
        },
        'office'
    )
    ->join('attached', 'socket.id', '=', 'attached.socket_id', 'left outer')
    ->join('users', 'socket.employee_id', '=', 'users.id', 'left outer')
    ->where('socket.id', $socketId)
    ->groupBy('users.name')
    ->get();

PHP 7.4's shorthand closures can make those selectSub statements look a bit smaller

    ->selectSub(
        fn(Builder $query) => $query->selectRaw('count(*)')->from('socket')
                                    ->leftJoin('container', 'socket.id', 'container.socket_id')
                                    ->where('socket.id', $socketId),
        'container'
    )

You can try checking the SQL for yourself by replacing ->get() with toSql() and dumping the result.

IGP
  • 14,160
  • 4
  • 26
  • 43
0

I solve it by using this query

$socjetsreport  = DB::table('socket')
    ->select("socket.id", "socket.name", 
    DB::raw("(SELECT COUNT(id) AS attchedcount FROM attached WHERE attached.socket_id=socket.id) as attchedcount"), 
    DB::raw("(SELECT COUNT(id) AS officecount FROM office WHERE office.socket_id=socket.id) as officecount"),
    DB::raw("(SELECT COUNT(id) AS containercount FROM container WHERE container.socket_id=socket.id) as containercount"),
    DB::raw("(SELECT COUNT(id) AS projectcount FROM project WHERE project.socket_id=socket.id) as projectcount"),
    DB::raw("(SELECT users.name AS employname FROM users WHERE users.id=socket.employee_id) as employname")
    )
    ->orderBy('socket.id', 'asc')
    ->get();
Ayman osman
  • 13
  • 1
  • 3