首页 > 解决方案 > 有没有办法用 Laravel Query Builder 重写这个原始 SQL 查询

问题描述

我有两张桌子:

产品

id | code | supplier_id |...

公司_产品

id | retail_price | copmany_id |...

有多个在线商店,我通过他们在本地存储的 API 提取产品。它几乎用于比较他们的价格、单位库存等,这可以通过所有商店都相同的产品代码来完成。

我只获取一次所有产品并每天更新几次。使用这个的其他公司,比方说“平台”,根据他们的合同有不同的产品价格,这些合同保存在第二张表中。

我想要实现的目标是列出所有产品,但只列出该产品代码的最便宜版本的产品。

我可以通过以下查询来实现它。

$products = DB::select(DB::raw(
    "select p.*, t.price_min
     from (select MAX(p.id) as id, p.code, MIN(cp.retail_price) as price_min
     from products as p
     left join company_product as cp on cp.product_id = p.id
     group by p.code) as t
     left join products as p on p.id = t.id"
));

这给了我想要的结果。但是,我有很多过滤器、排序、关系和分页要添加在此之上,这就是我尝试重写它的原因。

每一个建议都非常感谢。

标签: laravel

解决方案


首先,您可能想要的原始 MySQL 查询只是一个内部连接:

SELECT p.*, t.price_min
FROM products p
INNER JOIN
(
    SELECT p.code, MAX(p.id) AS max_id, MIN(cp.retail_price) AS price_min
    FROM products p
    INNER JOIN company_product cp ON cp.product_id = p.id
    GROUP BY p.code
) t
    ON p.id = t.max_id

至于 Laravel 代码,我们可以尝试在单独的变量中创建子查询,然后加入它:

$subquery = DB::table('products AS p')
    ->select([
        'p.code',
         DB::raw('MAX(p.id) AS max_id, MIN(cp.retail_price) AS price_min')])
    ->join('company_product AS cp', 'cp.product_id', '=', 'p.id')
    ->groupBy('p.code');

$query = DB::table('products AS p')
    ->select('p.*', 't.price_min')
    ->innerJoinSub($subquery, 't', function($join) {
        $join->on('p.id', '=', 't.max_id');
    })
    ->get();

推荐阅读