UNION操作用于合并两个或多个 SELECT 语句的结果集。
使用示例:
Db::field('name')
->table('think_user_0')
->union('SELECT name FROM think_user_1')
->union('SELECT name FROM think_user_2')
->select();
复制
闭包用法:
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();
或者
Db::field('name')
->table('think_user_0')
->union([
'SELECT name FROM think_user_1',
'SELECT name FROM think_user_2',
])
->select();
支持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();
每个union方法相当于一个独立的SELECT语句。
UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。
举例子
表:
ff_detail表结构:
ff_detail_201804等表结构:
需求:
ff_detail表会统计昨天一个订单中包含的设备的播放情况,pic_id代表设备id,date代表日期,play_time点播放次数。ff_detail_201805等为分表记录的是每个小时设备的播放情况,播放一次记录一次。因为数据特别巨大,所有会按照年月生成“ff_detail_年月”形式的分表。需求是按照日期统计每个订单每天播放次数。
代码:
/**
* 根据订单号统计播放次数
* @param string $orderId 订单号(子订单号)
* @param string $page
* @return mixed|false|array
*/
public function getCount($orderId=''){
if(empty($orderId)){
return false;
}
$picArr=Db::name('pic')->where('order_id',$orderId)->column('id,pic_id');
if(empty($picArr)){
return false;
}
$picIds=[];
foreach ($picArr as $pa){
$picIds[]=$pa['id'];
}
if(empty($picIds)){
return false;
}
$nowMonthDate=date('Ymd');
$nowMonth=date('Ym');
$selectTable='detail_'.$nowMonth;
$sqlArr=[];
//昨天之前的数据
$allDetail=Db::name('detail')
->where(['pic_id'=>['in',$picIds]])->field("sum(play_time) as timesum,date")
->group('date')->buildSql();
$sqlArr[]=$allDetail;
//今天的数据
$cpmMonthDetail=Db::name($selectTable)
->where(['pic_id'=>['in',$picIds],'create_date'=>$nowMonthDate])
->field("count(id) as timesum,create_date as date")
->group('create_date')->buildSql();
$sqlArr[]=$cpmMonthDetail;
//tp5有个问题,用了union之后用where和分页有有问题,所有通过构建子查询来达到目标。子查询里面本身要写完整的查询(指把所有需要查询的都union起来),再通过一个中间表(detail_temp)来组建查询ORM。
$temp=Db::name('cpm_detail_temp')
->field("count(id) as timesum,create_date as date")->union($sqlArr)->buildSql();
$finall = Db::table($temp." a")
->where(['timesum'=>['neq',0],'date'=>['neq',0]]) //把中间表数据过滤掉
->order('date desc')
->paginate(10,false,[
'type' => 'Bootstrap',
'var_page' => 'page',
'child_order_id'=>$orderId,
'path'=>"javascript:AjaxPage($orderId,[PAGE]);",
]);
$arrData=$finall->toArray();
$arrData=$arrData['data'];
if(!empty($arrData)){
foreach ($arrData as &$val){
$val['date']=date('Y-m-d',strtotime($val['date']));
}
}
return empty($finall)?false:['page'=>$finall->render(),'data'=>$arrData];
}