首先thinkPHP官方已经有了多表联查的demo,如下:
$rows = db('member')
->alias('m')
->join('agent a','m.m_pid=a.id','left')
->join('salesman s','a.a_pid=s.id')
->join('admin d','m.w_id=d.id')
->where('m.status',1)//条件:状态为1
->order('id desc')//根据id降序排列
->limit(10)//限制10条
->field(['m.*','a.uname as agentname','s.username','d.kname'])
->select();
现在我们需要处理的情况是:如果有当前录入表中(enter表)有关于线别、列车、位置、装车碳滑板的id,并没有下车的碳滑板id我们取的时候多表联查如何解决没有下车数据而要下车数据显示为空的情况呢?
public function lists($filter){
$join = [
['__USER__ au', 'e.up_user_id = au.id'],
['train_carbon uc','e.up_carbon_id = uc.id'],
['train_line l','l.id=e.line_id'],
['train_subway s','s.id=e.subway_id'],
['train_position p','p.id=e.position_id'],
];
$field = 'e.*,au.user_nickname as up_user_nickname,uc.sign as up_carbon_sign,uc.ini_ply,l.name as line_name,s.name as subway_name,p.name as position_name';
$reason_id = empty($filter['reason_id']) ? 0 : intval($filter['reason_id']);
if (!empty($reason_id)) {
array_push($join, [
'train_down d', 'd.id = e.down_reason_id'
]);
$field .= 'd.name as reason_name';
}
if(!empty($filter['down_start_time']) || !empty($filter['down_end_time'])){
array_push($join, [
'train_carbon dc', 'dc.id = e.down_carbon_id'
]);
$field .= 'dc.sign as down_carbon_sign';
}
$positions =implode(',',Db::name('position')->column('id'));
$lines = implode(',',Db::name('subway')->column('id'));
$exp =new \think\db\Expression('field(e.subway_id,'.$lines.'),field(e.position_id,'.$positions.')');
$enters = Db::name('enter')
->comment('查询录入列表数据源')
->alias('e')
->field($field)
->join($join)
->where('e.status',1)
->where('e.on_time', '>=', 0)
->where(function (Query $query) use ($filter) {
$line_id = empty($filter['line_id']) ? '' : intval($filter['line_id']);
if (!empty($line_id)) {
$query->where('e.line_id', $line_id);
}
$subway_id = empty($filter['subway_id']) ? '' : intval($filter['subway_id']);
if (!empty($subway_id)) {
$query->where('e.subway_id', $subway_id);
}
$position_id = empty($filter['position_id']) ? '' : intval($filter['position_id']);
if (!empty($position_id )) {
$query->where('e.position_id', $position_id );
}
$user_id = empty($filter['user_id']) ? '' : intval($filter['user_id']);
if (!empty($user_id )) {
$query->where('e.up_user_id',$user_id );
}
$reason_id = empty($filter['reason_id']) ? 0 : intval($filter['reason_id']);
if (!empty($reason_id)) {
$query->where('e.down_reason_id', $reason_id);
}
$upstartTime = empty($filter['up_start_time']) ? 0 : strtotime($filter['up_start_time']);
$upendTime = empty($filter['up_end_time']) ? 0 : strtotime($filter['up_end_time']);
if (!empty($upstartTime)) {
$query->where('e.on_time', '>=', $upstartTime);
}
if (!empty($upendTime)) {
$query->where('e.on_time', '<=', $upendTime);
}
$keyword = empty($filter['keyword']) ? '' : $filter['keyword'];
if (!empty($keyword)) {
$query->where('uc.sign', 'like', "%$keyword%");
}
$status = empty($filter['status']) ? '' : $filter['status'];
if ($status == 2) {
$query->where('e.status', 'eq', 2);
}elseif ($status == 1){
$query->where('e.status', 'eq', 1);
}else{
$query->where('e.status', 'in', '1,2');
}
if(!empty($filter['down_start_time']) || !empty($filter['down_end_time'])){
$downstartTime = empty($filter['down_start_time']) ? 0 : strtotime($filter['down_start_time']);
$downendTime = empty($filter['down_end_time']) ? 0 : strtotime($filter['down_end_time']);
if (!empty($downstartTime)) {
$query->where('e.time', '>=', $downstartTime);
}
if (!empty($downendTime)) {
$query->where('e.time', '<=', $downendTime);
}
}
})
->order($exp)
->paginate(10)->each(function($item){
if(!empty($item['down_reason_id'])){
$item['reason_name'] = Db::name('down')->where('id',$item['down_reason_id'])->value('name');
$item['down_carbon_sign'] = Db::name('carbon')->where('id',$item['down_carbon_id'])->value('sign');
}else{
$item['reason_name'] = null;
$item['down_carbon_sign'] = null;
}
if(!empty($item['down_user_id'])){
$item['down_user_nickname'] = Db::name('user')->where('id',$item['down_user_id'])->value('user_nickname');
}else{
$item['down_user_nickname'] = null;
}
$item['on_time'] = date('Y-m-d',$item['on_time']);
if (empty($item['time'])){
$item['time'] = null;
}else{
$item['time'] = date('Y-m-d',$item['time']);
}
if (empty($item['down_length'])){
$item['down_length'] = null;
}
if (empty($item['down_ply'])){
$item['down_ply'] = null;
}
return $item;
});
return $enters;
}
这是数据抓取层的代码段:
在进行多表联查时我用到了
use think\Db;
use think\db\Query;
两个助手函数。
query助手函数主要对数据查询进行闭包条件的查询,其中:
->where(function (Query $query) use ($filter) {
$line_id = empty($filter['line_id']) ? '' : intval($filter['line_id']);
if (!empty($line_id)) {
$query->where('e.line_id', $line_id);
}
$subway_id = empty($filter['subway_id']) ? '' : intval($filter['subway_id']);
if (!empty($subway_id)) {
$query->where('e.subway_id', $subway_id);
}
$position_id = empty($filter['position_id']) ? '' : intval($filter['position_id']);
if (!empty($position_id )) {
$query->where('e.position_id', $position_id );
}
$user_id = empty($filter['user_id']) ? '' : intval($filter['user_id']);
if (!empty($user_id )) {
$query->where('e.up_user_id',$user_id );
}
$reason_id = empty($filter['reason_id']) ? 0 : intval($filter['reason_id']);
if (!empty($reason_id)) {
$query->where('e.down_reason_id', $reason_id);
}
$upstartTime = empty($filter['up_start_time']) ? 0 : strtotime($filter['up_start_time']);
$upendTime = empty($filter['up_end_time']) ? 0 : strtotime($filter['up_end_time']);
if (!empty($upstartTime)) {
$query->where('e.on_time', '>=', $upstartTime);
}
if (!empty($upendTime)) {
$query->where('e.on_time', '<=', $upendTime);
}
$keyword = empty($filter['keyword']) ? '' : $filter['keyword'];
if (!empty($keyword)) {
$query->where('uc.sign', 'like', "%$keyword%");
}
$status = empty($filter['status']) ? '' : $filter['status'];
if ($status == 2) {
$query->where('e.status', 'eq', 2);
}elseif ($status == 1){
$query->where('e.status', 'eq', 1);
}else{
$query->where('e.status', 'in', '1,2');
}
if(!empty($filter['down_start_time']) || !empty($filter['down_end_time'])){
$downstartTime = empty($filter['down_start_time']) ? 0 : strtotime($filter['down_start_time']);
$downendTime = empty($filter['down_end_time']) ? 0 : strtotime($filter['down_end_time']);
if (!empty($downstartTime)) {
$query->where('e.time', '>=', $downstartTime);
}
if (!empty($downendTime)) {
$query->where('e.time', '<=', $downendTime);
}
}
})
就是query进行闭包条件查询的代码段。为了提升用户筛选条件的性能,在用户未输入其他添加的时候join的内容只是一些基础表的内容,当出现其他筛选条件的时候追加其他添加使用array_push函数做处理:
$reason_id = empty($filter['reason_id']) ? 0 : intval($filter['reason_id']);
if (!empty($reason_id)) {
array_push($join, [
'train_down d', 'd.id = e.down_reason_id'
]);
$field .= 'd.name as reason_name';
}
通常情况下我们都是用foreach进行对数组内容重组或者赋值,本节我使用each函数闭包达到上述效果:
each(function($item){
if(!empty($item['down_reason_id'])){
$item['reason_name'] = Db::name('down')->where('id',$item['down_reason_id'])->value('name');
$item['down_carbon_sign'] = Db::name('carbon')->where('id',$item['down_carbon_id'])->value('sign');
}else{
$item['reason_name'] = null;
$item['down_carbon_sign'] = null;
}
if(!empty($item['down_user_id'])){
$item['down_user_nickname'] = Db::name('user')->where('id',$item['down_user_id'])->value('user_nickname');
}else{
$item['down_user_nickname'] = null;
}
$item['on_time'] = date('Y-m-d',$item['on_time']);
if (empty($item['time'])){
$item['time'] = null;
}else{
$item['time'] = date('Y-m-d',$item['time']);
}
if (empty($item['down_length'])){
$item['down_length'] = null;
}
if (empty($item['down_ply'])){
$item['down_ply'] = null;
}
return $item;
});
在处理完毕以后,因为闭包实在查询完毕后进行的,所以我们必须return $item 把值返回给上一层。