laravel join 子查询 joinSub的源码剖析

   日期:2020-09-25     浏览:115    评论:0    
核心提示:实现join中使用子查询的需求。实现方法1:joinSub实现方法2:join+getBindings+addBinding源码剖析joinSub方法

想实现join中使用子查询的需求,于是根据文档以及源码寻找方法

laravel leftjoin on orOn的源码剖析

文章目录

      • 想要实现的原生sql
        • 官方文档给的方法(子查询联接)
      • 实现方法1:joinSub
      • 实现方法2:join+getBindings+addBinding
      • 源码剖析joinSub方法

想要实现的原生sql

SELECt
*
FROM
	`a`
	LEFT JOIN ( SELECt * FROM `b` WHERe `type` = 2 ) AS b 
	AND ( `a`.`a` = `b`.`a` AND `a`.`b` = `b`.`b` AND `a`.`c` = `b`.`c` ) 
	OR  ( `a`.`a` = `b`.`a` AND `a`.`b` = `b`.`b` AND `a`.`d` = `b`.`d` ) 

官方文档给的方法(子查询联接)

您可以使用joinSubleftJoinSubrightJoinSub方法加入查询的子查询。这些方法中的每一个都接收三个参数:子查询,其表别名和定义相关列的Closure:

$latestPosts = DB::table('posts')
                   ->select('user_id', DB::raw('MAX(created_at) as last_post_created_at'))
                   ->where('is_published', true)
                   ->groupBy('user_id');

$users = DB::table('users')
        ->joinSub($latestPosts, 'latest_posts', function ($join) { 
            $join->on('users.id', '=', 'latest_posts.user_id');
        })->get();

实现方法1:joinSub

$query = DB::table('table_name2')->where('type','=',2);
$info = DB::table('table_name')
            ->joinSub($query,'table_name2', function ($join) { 
                $join->on([
                    ['table_name.a', '=', 'table_name2.a'],
                    ['table_name.b', '=', 'table_name2.b'],
                    ['table_name.c', '=', 'table_name2.c'],
                ])->orOn([
                    ['table_name.a', '=', 'table_name2.a'],
                    ['table_name.b', '=', 'table_name2.b'],
                    ['table_name.d', '=', 'table_name2.d'],
                ]);
            })->get();

实现方法2:join+getBindings+addBinding

ps: join+子查询只有用到where的时候才需要addBinding,否则sql语句会只有’?’

$query = DB::table('table_name2')->where('type','=',2);
 
$info = DB::table('table_name')
            ->join(DB::raw('('.$query->toSql().') as table_name2'), function ($join) use ($query) { 
                $join->on([
                    ['table_name.a', '=', 'table_name2.a'],
                    ['table_name.b', '=', 'table_name2.b'],
                    ['table_name.c', '=', 'table_name2.c'],
                ])->orOn([
                        ['table_name.a', '=', 'table_name2.a'],
                        ['table_name.b', '=', 'table_name2.b'],
                        ['table_name.d', '=', 'table_name2.d'],
                    ])->addBinding($query->getBindings());
            })->get();

源码剖析joinSub方法

文件地址:/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php


 public function joinSub($query, $as, $first, $operator = null, $second = null, $type = 'inner', $where = false)
 { 
 	 // 结果:query为原生sql,bindings为getBindings的绑定参数
 	 // createSub方法见下方
     [$query, $bindings] = $this->createSub($query);

     $expression = '('.$query.') as '.$this->grammar->wrapTable($as);

     $this->addBinding($bindings, 'join');

     return $this->join(new Expression($expression), $first, $operator, $second, $type, $where);
 }

 
 protected function createSub($query)
 { 
     // If the given query is a Closure, we will execute it while passing in a new
     // query instance to the Closure. This will give the developer a chance to
     // format and work with the query before we cast it to a raw SQL string.
     if ($query instanceof Closure) { 
         $callback = $query;

         $callback($query = $this->forSubQuery());
     }

     return $this->parseSub($query);
 }
 
  protected function parseSub($query)
  { 
      if ($query instanceof self || $query instanceof EloquentBuilder) { 
          return [$query->toSql(), $query->getBindings()];
      } elseif (is_string($query)) { 
          return [$query, []];
      } else { 
          throw new InvalidArgumentException(
              'A subquery must be a query builder instance, a Closure, or a string.'
          );
      }
  }

  public function addBinding($value, $type = 'where')
  { 
      if (! array_key_exists($type, $this->bindings)) { 
          throw new InvalidArgumentException("Invalid binding type: { $type}.");
      }

      if (is_array($value)) { 
          $this->bindings[$type] = array_values(array_merge($this->bindings[$type], $value));
      } else { 
          $this->bindings[$type][] = $value;
      }

      return $this;
  }

上述代码已用model的方式实现了原生sql

laravel join 子查询 joinSub的源码剖析就到这了,希望文章可以帮忙解决你的难题,期待你的关注

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服