前言
之前有做过laravel使用union的:laravelDb查询数据库使用union合并两个不相关的表,新增不存在的字段,并赋予默认值
那么thinkphp又要如何做呢?
我们可以先查看官方文档:https://static.kancloud.cn/manual/thinkphp5/118084
使用案例
Db::field('name') ->table('think_user_0') ->union(function($query){ $query->field('name')->table('think_user_1'); }) ->union(function($query){ $query->field('name')->table('think_user_2'); }) ->select();
当然,官方的这种办法是可以实现的,但是明显还不够优雅,我们可以结合buildSql构造子查询一起来使用:https://static.kancloud.cn/manual/thinkphp5/135185
使用例子
$subQuery = Db::table('think_user') ->field('id,name') ->where('id','>',10) ->buildSql();
实际案例
需求分析
今天有一个需求,需要写一个全局搜索接口,系统的数据很多,包括新闻,文章,协会专家,供应采购等等数据,覆盖多个表的数据,每部分的内容都太一样,当然你可以直接简单粗暴的使用遍历查询每个表的数据,再进行合并,但是这样明显不够方便,开销也大,而且肯定还会涉及数据分页,手写分页也是挺麻烦的,所以我们可以选择使用union直接一步到位,UNION操作就是用于合并两个或多个 SELECT 语句的结果集。
几个数据库表结构
代码实现
'' AS title
表示新增不存在的字段,并赋予默认值为空字符
//全局搜索接口 public function search() { $request = request()->post(); $limit = $request['limit'] ?? 10; $title = $request['title'] ?? ''; //菜单导航:1=新闻中心,2=网上办事,3=法规标准,4=协会专家,5=供应,6=采购 $where = []; if ($title) $where['name'] = ['like', "%" . $title . "%"]; $sql4 = DB::name("expert")->field("id, name, '' AS title, tags, '' AS url , FROM_UNIXTIME(createtime) as createtime, 4 AS menu") ->where($where) ->buildSql(); $sql5 =DB::name("supply")->field("id, name, '' AS title, tags, '' AS url , FROM_UNIXTIME(createtime) as createtime, 5 AS menu") ->where($where) ->buildSql(); $where = []; if ($title) $where['title'] = ['like', "%" . $title . "%"]; $sql1 = DB::name("news")->field("id, '' AS name, title, tags, '' AS url , FROM_UNIXTIME(createtime) as createtime, 1 AS menu") ->where($where) ->buildSql(); $sql2 = DB::name("work")->field("id, '' AS name, title, tags, url, FROM_UNIXTIME(createtime) as createtime, 2 AS menu") ->where($where) ->buildSql(); $sql3 = DB::name("laws")->field("id, '' AS name, title, tags, '' AS url , FROM_UNIXTIME(createtime) as createtime, 3 AS menu") ->where($where) ->buildSql(); $sql6 = DB::name("purchase")->field("id, '' AS name, title, tags, '' AS url, FROM_UNIXTIME(createtime) as createtime, 6 AS menu") ->where($where); //合并 $sql = $sql6->union([$sql1, $sql2, $sql3, $sql4, $sql5])->buildSql(); $data = Db::table($sql.' a')->order("a.createtime desc")->paginate($limit); $this->success('获取成功', $data); }
结果
注意
UNION 内部的 SELECT 语句必须拥有相同数量的列
。列也必须拥有相似的数据类型
。同时,每条 SELECT 语句中的列的顺序必须相同
。
UNION与UNION ALL的区别
当使用 UNION 时,MySQL 会把结果集中重复的记录删掉,而使用 UNION ALL ,MySQL 会把所有的记录返回,且效率高于 UNION。
想使用UNION ALL也非常简单
Db::field('name') ->table('think_user_0') ->unionAll('SELECT name FROM think_user_1') ->unionAll('SELECT name FROM think_user_2') ->select();
或者
Db::field('name') ->table('think_user_0') ->union(['SELECT name FROM think_user_1', 'SELECT name FROM think_user_2'], true) ->select();