SQL Union实现子母单列表展示

【需求分析】

系统接入ERP,订单会根据商品的发货仓进行拆单,所以订单之间不再是单独的关系,而有了子单母单的概念。在做最小的改动的情况下,数据库的改造是在订单表上增加了parent_order_sn字段,所谓的母订单号。如果订单A被拆单,则A应该是母订单,订单状态是‘已拆单’。通过parent_order_sn=‘A订单号’去查询,可以查到对应的子订单记录。

【问题再现】

之前我一直在负责和ERP系统对接的项目,所以对原系统的订单查询改造是另一个同事写的。最近和ERP的对接做了一些修改,可能母订单A拆除的子订单B和子订单C会再一次进行拆分,即订单B可以是一个母订单,B下面有其他两个子订单D和子订单E。在进行这一轮修改的测试,订单列表查询偶尔出现了错位的情况,如下:

在这里插入图片描述

正确的展示,如下:

在这里插入图片描述

但这种错误现象也不是百分百存在,之前都没有发现有问题。看别人的代码, 真的是不想做的一件事,特别是这种复杂问题的代码,上线前一天看了下,觉得代码写的太复杂了,找不到问题,还是不动了。而就在昨天上线的上午,出现频率比较高,就乖乖又去看代码了,按照代码实现逻辑理了一遍,发现其实思路就是不对的,分页查询一直是有问题的,也没有人注意到。

【代码重写】

原来的代码实现思路是:将所有的母单排除,查询出所有的子单,并加上分页一页10条。然后循环结果集,从子单上获取相关订单信息组装到母单上。

而这样的结果,就不对了。如果在10条记录中,有子母单的订单,查询到的结果数就一直是不确定的。最简单的设想,前10条都是子母单的订单,那么其实只会展示5个订单,而每页的订单数量是根据子母单数量的多少而改变的,显然是不对的。

既然找到问题了,而且代码实现完全不对,就直接选择换思路重写代码,不改也逃不过了。

现在的代码实现思路是:将所有的母单查询到,查询完母单后,再去循环,判断如果有子单的情况下,去查询订单下所有的子单,组装到母订单上。这样不管有多少子母单的情况,有子单算一单,没有子单也算一单,也不用关心这个母单是不是由一个子单继续拆分的,也保证了分页的数量是正确的。

【实现难题】

既然思路确定了,接下来就是写代码了。但是问题来了,我不知道怎么样把所有的母单查询到,而且是不重复的所有母单。下面是数据库中订单的截图:

在这里插入图片描述

总结一下,其实就是两种情况:

  1. parent_order_sn那一列可能是没有值的,也就是算是一个母订单;
  2. parent_order_sn有值的情况下,一定是会有多条的。

我怎么保证一个sql能查询到没有问题的分页结果,parent_order_sn有值的情况下,需要Distinct,没有值的情况下,需要查出所有,脑子里开始想SQL怎么写,GROUP BY,DISTINCT,IF,CASE…WHEN…各种SQL函数,还是不知道这个SQL该怎么写了。

中午吃完饭就开始想,到两点要开始工作了,和前端说了句,这一个SQL没法写,写不出来,我只能查出正确的结果之后,再自己去做分页分组的处理。说完,我就想到了既然一个SQL不能实现,我就用两个SQL去查,然后合并结果集。三两分钟,不重复的母单的SQL查询就写出来了。如下:

SELECT
	*
FROM
	(
		SELECT
			t.*, cus.customer_title
		FROM
			wms_orders t
		LEFT JOIN wms_customer cus ON cus.id = t.buyer_id
		WHERE
			t.order_status != 100
		AND t.comp_id = 8815
		AND t.parent_order_sn IS NOT NULL
		AND t.parent_order_sn != ''
		GROUP BY
			parent_order_sn
		ORDER BY
			t.id_ DESC
	) a
UNION
	SELECT
		*
	FROM
		(
			SELECT
				t.*, cus.customer_title
			FROM
				wms_orders t
			LEFT JOIN wms_customer cus ON cus.id = t.buyer_id
			WHERE
				t.order_status != 100
			AND t.comp_id = 8815
			AND (
				t.parent_order_sn IS NULL
				OR t.parent_order_sn = ''
			)
			ORDER BY
				t.id_ DESC
		) b
	ORDER BY
		id_ DESC

其实很简单,就是两种分开写,用union将两个SQL合并,查询不重复的结果集。

第一个SQL对应parent_order_sn有值的情况下,用Group By按parent_order_sn字段分组,并且,将第二种情况parent_order_sn没有值的排除。

第二个SQL对应parent_order_sn没有值的情况,并且将第一种情况parent_order_sn有值的排除。

最后用union,并且按id倒叙排序。

【心得总结】

  1. 代码实现前,思路是很重要的,思路是对的,才能保证结果是对的。

同事做之前就和她讨论过该怎么实现,可是结果还是按照她自己的想法去做的,之前没有发现问题,我也就没有去看她是怎么实现的。看完后,才发现思路是不对的,结果就不一定能保证对了。

  1. 代码重写,双方都不是滋味。

出问题的代码,不是自己写的,一万个不想去看别人写的代码。出问题的代码,是自己写的,结果不对,于是被别人推翻重写,一万个怀疑我写的代码怎么可能不对。讲真,这应该是这行业最真实的心理写照。

  1. 代码是需要积累的,项目经验是宝贵的。

在工作中,每一个需求,每一次代码实现,都是我们积累的财富。代码写的多了,项目中遇到的情况多了,总是会有价值的。

  1. 不要总想着逃避,其实没有那么困难。

时间长了,心态不太好了,总想着问题和我无关,少做一点,让自己轻松一点。出问题了,就觉得牵扯的东西太多了,不想去碰,等到不得不解决的那一刻才去做,而不是主动去处理问题。换一个心态,或许结果还是美好的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值