关于 sql 关联查询 解决方案 已解决

1. 问题描述

有两个表
goods 表内字段 id,name,type,等等其他字段 一对多关系
表二 goods_log 表字段 id,goods_id,createtime 等其他字段
现在需要关联两个表,需求如下,通过筛选时间,今日,本周,本月,本年来排序
效果图如下
关于 sql 关联查询 解决方案

1. 我的解决方案如下两种(未解决)

1). 先查询goods表数据 ,再关联表goods_id ,这个的话,我只能再循环一次数据来排序,感觉复杂了许多,代码如下

$whereTime = $this->request->param('time')??'d';
switch ($whereTime) {
            case 'w':
                $whereTime = 'w';
                break;
            case 'm':
                $whereTime = 'm';
                break;
            case 'y':
                $whereTime = 'y';
                break;
            default:
                $whereTime = 'd';
                break;
        }
$data = Db::name('goods')->field('id,name,type')
          ->paginate()
          ->each(function($item, $key) use ($whereTime) {
               $item['click'] = Db::name('goods_log')->where('goods_id',$item['id'])->whereTime('createtime',$whereTime)->count();
               $item['contrast'] = 5;//这个是对比率,先写死
               $item['symbol']   = $item['click']/$item['contrast'] > 0 ? 0 : 1 ;//0=降下 1=上升 这个是图标显示
                    return $item;
       });

2). 然后尝试第二种写法,通过时间筛选了,这样写又不符合效果图预期,假入今日没有新增数据,就查为空了,代码如下

$list = Db::name('goods')->alias('g')
        ->field('g.id,g.name,count(l.goods_id) as click,l.createtime')
        ->join('goods_log l','g.id = l.goods_id','LEFT')
        ->whereTime('l.createtime',$whereTime)
        ->group('l.goods_id')
        ->order('click desc,g.id desc')
        ->select();

虚心请教大佬们有没有更优的解决方案,本人数据库子查询方面还欠缺。

3.解决方案如下 根据大佬指示,自己写了一遍,如下

当前使用的是tp框架

//模型
public function goods()
{
    return $this->hasMany('goods_log');
}

//控制器
$limit = 5; //每页显示条数
$page  = 1; //第几页
$query = Goods::field('id,name,type')->withCount([
              'goods' => function( $query ) use ( $whereTime ){
                     $query->whereTime('createtime',$whereTime);
               }
         ]);
$data = $query->page($page,$limit)
              ->order('goods_count desc,id desc')
              ->select();
$total = $query->count(); //返回总数
$this->success('查询成功',['total'=>$total,'page'=>$page,'limit'=>$limit,'data'=>$data]);

打印的sql与数据

SELECT `id`,`name`,`type`,(SELECT COUNT(*) AS tp_count FROM `fa_goods_log` WHERE (  `createtime` BETWEEN 1672502400 AND 1704038400  AND ( `goods_id` = fa_goods.id ) ) AND `fa_goods_log`.`deletetime` IS NULL LIMIT 1) AS `goods_count` FROM `fa_goods` ORDER BY `goods_count` DESC,`id` DESC LIMIT 0,5

关于 sql 关联查询 解决方案 已解决
剩下的就循环一下处理对比率,
再次感谢

《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
最佳答案

在goods模型里面创建一对多方法

 public function goods()
 {
    return $this->hasMany(GoodsLog::class, 'good_id');
 }
//控制器
Goods::query()->withCount([
            'goods as today' => function(Builder $builder) use ($whereTime){
                $builder->whereTime('createtime',$whereTime);
            },
            'goods as week' => function(Builder $builder) use ($week){
                $builder->whereTime('createtime',$week);
            },
            'goods as month' => function(Builder $builder) use ($month){
                $builder->whereTime('createtime',$month);
            },
            'goods as year' => function(Builder $builder) use ($year){
                $builder->whereTime('createtime',$year);
            },
        ])->get();

按道理就是这样 然后其他得就自己操作就可以了,文档链接模型关联《Laravel 8 中文文档》

1年前 评论
凌晨三点半的卢本伟 (楼主) 1年前
讨论数量: 11

好像有个地方是专门踩缝纫机来着 :confused:

1年前 评论
oceanjiayu 1年前
凌晨三点半的卢本伟 (楼主) 1年前

在goods模型里面创建一对多方法

 public function goods()
 {
    return $this->hasMany(GoodsLog::class, 'good_id');
 }
//控制器
Goods::query()->withCount([
            'goods as today' => function(Builder $builder) use ($whereTime){
                $builder->whereTime('createtime',$whereTime);
            },
            'goods as week' => function(Builder $builder) use ($week){
                $builder->whereTime('createtime',$week);
            },
            'goods as month' => function(Builder $builder) use ($month){
                $builder->whereTime('createtime',$month);
            },
            'goods as year' => function(Builder $builder) use ($year){
                $builder->whereTime('createtime',$year);
            },
        ])->get();

按道理就是这样 然后其他得就自己操作就可以了,文档链接模型关联《Laravel 8 中文文档》

1年前 评论
凌晨三点半的卢本伟 (楼主) 1年前

第2种写法中,用左外联接,左外连接的特点是左边表的每条记录都会出现,所以不会出现“假如没有新增数据就为空”,不可能为空的,就是为0,但是记录有。

然后,最后的涨幅看是用同比还是环比,单独处理就行了。就是查完完后,对每条记录单独处理即可。

1年前 评论
凌晨三点半的卢本伟 (楼主) 1年前

其实这种按年月日统计的,一般都会有一个表专门维护的,不可能直接查原始数据

1年前 评论
凌晨三点半的卢本伟 (楼主) 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!