【问题标题】:Laravel multiple count on multiple joinLaravel 多重计数多重连接
【发布时间】: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

【问题讨论】:

    标签: laravel


    【解决方案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。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-23
        • 2012-10-29
        • 2023-03-07
        • 2014-07-01
        • 1970-01-01
        • 2018-06-03
        • 2011-10-29
        相关资源
        最近更新 更多