Laravel 多重计数多重连接
Posted
技术标签:
【中文标题】Laravel 多重计数多重连接【英文标题】:Laravel multiple count on multiple join 【发布时间】:2021-07-29 20:06:16 【问题描述】:我有四个表套接字,办公室,容器,项目我需要将这些表与 primey 表套接字连接,并通过 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();
我尝试在 mysql 查询中应用它,它运行良好,但在 laravel 中它只是给我错误的计数。
这是我的 MySQL 查询:
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
【问题讨论】:
【参考方案1】:我通过使用这个查询来解决它
$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();
【讨论】:
【参考方案2】:由于LEFT OUTER JOIN is the same as LEFT JOIN,您可以只使用查询构建器的leftJoin()
方法。
对于SELECT
语句中的所有子查询,您应该使用查询构建器的selectSub()
方法。
/** * 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 );
生成的查询如下所示:
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();
如果你挂断了使用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 的速记闭包可以使那些 selectSub 语句看起来更小
->selectSub(
fn(Builder $query) => $query->selectRaw('count(*)')->from('socket')
->leftJoin('container', 'socket.id', 'container.socket_id')
->where('socket.id', $socketId),
'container'
)
您可以通过将->get()
替换为toSql()
并转储结果来尝试自己检查SQL。
【讨论】:
以上是关于Laravel 多重计数多重连接的主要内容,如果未能解决你的问题,请参考以下文章