Laravel嵌套子查询 临时表

Laravel嵌套子查询 临时表

    • 笔者需求
    • 表格情况
    • 原始SQL实现
    • 原始SQL性能分析图
    • 使用Laravel框架实现
    • 遇到的问题与解决方式
    • Laravel生成的SQL
    • 最终实现了Laravel框架中,基于DB类使用一个查询语句,完成查询需求。

笔者需求

根据订单表的缺货订单查询订单详情,订单项目详情,产品详情,产品类别详情,总库存数量,以及某个仓库库存数量;以便生产和采购进行产品生产与采购。
并使用一个SQL语句完成查询;
Laravel框架版本5.8;

表格情况

包含表格:订单表,订单详情表,产品详情表,产品类别表,产品库存表;

  1. 订单表关键字段:id,order_code,status;
  2. 订单详情表关键字段:id,product_id,order_id,quantity;
  3. 产品详情表:id,sku,cn_name;
  4. 产品类别表:id,product_id,category_id;
  5. 库存表:id,product_id,warehouse_id;

原始SQL实现

SELECT
	order_code,
	product_code,
	cn_name,
	tabel_b.product_id,
	item_id,
	self,
	tabel_b.quantity,
	in_quantity,
	in_quantity_lock,
	sum( CASE inven.warehouse_id WHEN 1 THEN inven.quantity ELSE 0 END ) dg_quantity 
FROM
	(
SELECT
	order_code,
	sku AS product_code,
	cn_name,
	tabel_a.product_id,
	item_id,
	self,
	tabel_a.quantity,
	sum( inventory.quantity ) in_quantity,
	sum( inventory.quantity_lock ) in_quantity_lock 
FROM
	(
SELECT
	orders.order_code,
	product.sku,
	cn_name,
	items.product_id,
	items.id AS item_id,
	sum( CASE cate.category_id WHEN 26 THEN 1 ELSE 0 END ) self,
	items.quantity 
FROM
	erp_orders_detail items
	LEFT JOIN erp_orders orders ON items.order_id = orders.id
	LEFT JOIN erp_product_category cate ON cate.product_id = items.product_id
	LEFT JOIN erp_product product ON items.product_id = product.id 
WHERE
	orders.STATUS = 4 
GROUP BY
	item_id,
	items.product_id 
	) tabel_a
	LEFT JOIN erp_inventory inventory ON tabel_a.product_id = inventory.product_id 
GROUP BY
	item_id 
	) tabel_b
	LEFT JOIN erp_inventory inven ON inven.product_id = tabel_b.product_id 
GROUP BY
	item_id 
ORDER BY
	self DESC

原始SQL性能分析图

Laravel嵌套子查询 临时表_第1张图片
除了两个无索引全表扫描的临时表外,性能还算OK

使用Laravel框架实现

use Illuminate\Support\Facades\DB;
use Illuminate\Database\Query\Builder as QBuilder;
//上面是引用类,为区别于Eloquent\Builder,重命名为QBuilder
//下面的是构建查询的核心代码
        //要点:用于构造子查询的临时表,无get方法
        $temp_a=DB::table('erp_orders_detail as items')
            ->leftJoin('erp_orders as orders','items.order_id','=','orders.id')
            ->leftJoin('erp_product as product','product.id','=','items.product_id')
            ->leftJoin('erp_product_category as cate','cate.product_id','=','items.product_id')
            ->where('orders.status','=',4)
            ->selectRaw('orders.order_code,items.quantity as item_quantity,items.product_id,items.id as item_id,product.sku,product.cn_name,sum(case cate.category_id when 26 then 1 else 0 end) self')
            ->groupBy('items.id');
        $temp_b=DB::table('erp_inventory as inventory')
            ->rightJoinSub($temp_a,'table_a',function(QBuilder $query){
                $query->on('inventory.product_id','=','table_a.product_id');
            })
            ->selectRaw('table_a.*,sum( inventory.quantity ) in_quantity,sum( inventory.quantity_lock ) in_quantity_lock ')
            ->groupBy('table_a.item_id');
        $result=DB::table('erp_inventory as inven')
            ->rightJoinSub($temp_b,'table_b',function(QBuilder $query){
                $query->on('inven.product_id','=','table_b.product_id');
            })
            ->selectRaw('table_b.*,sum( CASE inven.warehouse_id WHEN 1 THEN inven.quantity ELSE 0 END ) dg_quantity')
            ->groupBy('table_b.item_id')
            ->orderByDesc('self')
            ->get();

遇到的问题与解决方式

  1. 类别表中,一个产品,属于多个类别,且自产属性category_id=26,若无此项记录,则认为是外购;问题点:不能使用where category_id=26这样的查法,因为会剔除非自产类别;解决方法:使用select的时候用case 0,1,然后分组求和。其结果为1的,是自产,结果为0的是外购,这样就不会剔除外购了。
  2. 因为要查总的库存数量,需要再次分组,因为第一步使用了分组,就需要使用子查询,临时表来进行join操作,再次分组查询查询;
    3.Laravel中使用子查询,嵌套查询方式,查询手册后,构建子查询的核心要点:使用简单查询的方式查询,但是最后不使用get()方法;再使用Illuminate\Database\Query\Builder构建为子查询语句;
  3. 原始SQL中是用的leftjoin,但是在laravel中使用的是rightjoin;因为from后面带的表格不一样;
  4. 需要关闭框架默认的MySQL严格模式,位于database.php配置文件中;修改为’strict’ => false,//严格模式,1:严格group和聚合函数的使用

Laravel生成的SQL

PREPARE SELECT
	table_b.*,
	SUM( CASE inven.warehouse_id WHEN 1 THEN inven.quantity ELSE 0 END ) dg_quantity 
FROM
	`erp_inventory` AS `inven`
	RIGHT JOIN (
SELECT
	table_a.*,
	SUM( inventory.quantity ) in_quantity,
	SUM( inventory.quantity_lock ) in_quantity_lock 
FROM
	`erp_inventory` AS `inventory`
	RIGHT JOIN (
SELECT
	orders.order_code,
	items.quantity AS item_quantity,
	items.product_id,
	items.id AS item_id,
	product.sku,
	product.cn_name,
	SUM( CASE cate.category_id WHEN 26 THEN 1 ELSE 0 END ) self 
FROM
	`erp_orders_detail` AS `items`
	LEFT JOIN `erp_orders` AS `orders` ON `items`.`order_id` = `orders`.`id`
	LEFT JOIN `erp_product` AS `product` ON `product`.`id` = `items`.`product_id`
	LEFT JOIN `erp_product_category` AS `cate` ON `cate`.`product_id` = `items`.`product_id` 
WHERE
	`orders`.`status` = ? 
GROUP BY
	`items`.`id` 
	) AS `table_a` ON `inventory`.`product_id` = `table_a`.`product_id` 
GROUP BY
	`table_a`.`item_id` 
	) AS `table_b` ON `inven`.`product_id` = `table_b`.`product_id` 
GROUP BY
	`table_b`.`item_id` 
ORDER BY
	`self` DESC

最终实现了Laravel框架中,基于DB类使用一个查询语句,完成查询需求。

比起这个玩法要花俏一些了:$result=DB::select(“原始SQL”)

你可能感兴趣的:(SQL语句基础)