如何用 Laravel 的 Model 或者 DB 格式 实现以下需求呢

cs_goods 表结构

id goods_id cs_merchant_id created_at
1 234 3 2019-07-09 19:45:33
2 33 3 2019-07-10 19:45:33
3 44 3 2019-07-11 19:45:33
4 55 3 2019-07-01 19:45:33
5 33 5 2019-07-02 19:45:33
6 44 5 2019-07-08 19:45:33
7 55 6 2019-07-06 19:45:33

需求:获取 cs_goods 表中的所有商品,但同一个超市最多只能出现 3 个商品(cs_merchant_id 是超市id),并用created_at 进行倒序排列,最后的结果应该是 3 2 1 6 7 5

除了循环 还有没有更高效的写法

原生sql:
SELECT a.* FROM cs_goods a WHERE ( SELECT COUNT(*) FROM cs_goods WHERE cs_merchant_id = a.cs_merchant_id AND id > a.id ) < 3 ORDER BY a.created_at desc;

请问不用原生sql语句,怎么用 Model 或者 DB 格式进行查询?

《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
最佳答案

首先我认为你给出的原生SQL是错误的,查询结果并不符合你所预期的
正确的原生SQL应该是这样的:

  1. 使用子查询的方式
    SELECT
    `a`.* 
    FROM
    `cs_goods` AS `a` 
    WHERE
    ( SELECT COUNT(`b`.`id`)  FROM `cs_goods` AS b WHERE `b`.`cs_merchant_id` = `a`.`cs_merchant_id` AND `b`.`created_at` > `a`.`created_at` ) < 3 
    ORDER BY
    `a`.`created_at` DESC;
  2. 使用关联查询的方式
    SELECT
    `a`.* 
    FROM
    `cs_goods` AS `a`
    LEFT JOIN `cs_goods` AS `b` ON `a`.`cs_merchant_id` = `b`.`cs_merchant_id` 
    AND `b`.`created_at` > `a`.`created_at` 
    GROUP BY
    `a`.`id` 
    HAVING
    COUNT( b.id ) < 3 
    ORDER BY
    `a`.`created_at` DESC

然后我们可以使用DB类来构建以上SQL,此处给出方式2 关联查询的构建代码:

    \DB::table('cs_goods as a')
        ->select('a.*')
        ->leftJoin('cs_goods as b', function ($join){
            return $join->on('a.cs_merchant_id','=','b.cs_merchant_id')
                ->on('b.created_at','>','a.created_at');
        })
        ->groupBy('a.id')
        ->havingRaw('COUNT(b.id) < 3')
        ->orderByDesc('a.created_at')
        ->toSql();

最后,像一些复杂查询的SQL,是不是直接先原生SQL更好一些呢?

4年前 评论
一个人的江湖 (楼主) 4年前
一个人的江湖 (楼主) 4年前
lovecn 4年前
i-am-king (作者) 4年前
讨论数量: 4

感觉可以采用 DB::raw() 来实现

4年前 评论
_杭城浪子 4年前

Post::has('comments', '>=', 3)->get(); 可以了解一下

4年前 评论
一个人的江湖 (楼主) 4年前
一个人的江湖 (楼主) 4年前
半人间 (作者) 4年前
eeecm 4年前

@Summer
@leo
大佬能提供一些思路吗 :pray:

4年前 评论

首先我认为你给出的原生SQL是错误的,查询结果并不符合你所预期的
正确的原生SQL应该是这样的:

  1. 使用子查询的方式
    SELECT
    `a`.* 
    FROM
    `cs_goods` AS `a` 
    WHERE
    ( SELECT COUNT(`b`.`id`)  FROM `cs_goods` AS b WHERE `b`.`cs_merchant_id` = `a`.`cs_merchant_id` AND `b`.`created_at` > `a`.`created_at` ) < 3 
    ORDER BY
    `a`.`created_at` DESC;
  2. 使用关联查询的方式
    SELECT
    `a`.* 
    FROM
    `cs_goods` AS `a`
    LEFT JOIN `cs_goods` AS `b` ON `a`.`cs_merchant_id` = `b`.`cs_merchant_id` 
    AND `b`.`created_at` > `a`.`created_at` 
    GROUP BY
    `a`.`id` 
    HAVING
    COUNT( b.id ) < 3 
    ORDER BY
    `a`.`created_at` DESC

然后我们可以使用DB类来构建以上SQL,此处给出方式2 关联查询的构建代码:

    \DB::table('cs_goods as a')
        ->select('a.*')
        ->leftJoin('cs_goods as b', function ($join){
            return $join->on('a.cs_merchant_id','=','b.cs_merchant_id')
                ->on('b.created_at','>','a.created_at');
        })
        ->groupBy('a.id')
        ->havingRaw('COUNT(b.id) < 3')
        ->orderByDesc('a.created_at')
        ->toSql();

最后,像一些复杂查询的SQL,是不是直接先原生SQL更好一些呢?

4年前 评论
一个人的江湖 (楼主) 4年前
一个人的江湖 (楼主) 4年前
lovecn 4年前
i-am-king (作者) 4年前

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