数据校验和时间段重合处理:一个有趣的业务数据案例分享

1. 需求背景(可跳过)

在标准的采购流程管理中有一处为“供应商配额管理”的模块,见名知意,就是控制时间段内供应商的配额比例(合计100%)。
例如:(数据样例)

1.1 原方案数据库表设计:单据表头记录采购组织、物料等信息,表头关联表中记录时间段信息,时间段表的关联表记录供应商信息(这里只介绍核心业务数据结构)
原页面设计

1.2 数据流向变更:在以物料为核心的原设计背景下,根据客户的实际需求需要增加一张前置单据。该单据需要支持 “多物料,多时间段,多供应商” 批量录入信息。
(由于后续业务与 “配额” 原单数据关联复杂,增加前置单据既可以满足需求,又可以保证最小化改动)
前置单据页面设计

2. 思路整理(可跳过)

变化方向主要为以下两点(此次前置单据的增加不仅是数据流入和物料维度的变化,也是对原方案“校验逻辑” 和 “更新时间段” 逻辑的补充):

2.1 校验逻辑增加:数据流入的变化为“单物料,多时间段,多供应商” ——> “多物料,多时间段,多供应商”,且由三层表结构打平为一层
2.2 增加时间段重合的处理逻辑(后续有详细说明)

3. 方案介绍(重点)

`
首先,我们可以先列举时间段更新时间段的几种情景:

可以想到这样一种场景,两列列车相向行驶,一辆列车有7节车厢,另一辆则为8节,他们形驶而过的整个过程,共有多少种情况?

结果是5种
在这里插入图片描述
如果两辆列车长度交换,则会新增一种情况
在这里插入图片描述
如果两辆列车长度相等,则又会多出一种情况
在这里插入图片描述
根据上述列举,我们可以结论:时间段更新时间段共有7种场景

可以看到,不同场景可以根据两段时间段的头尾比较来确定

  1. 倘若在界面一行行新增数据,我们可以通过获取前台用户输入的值变更来校验数据,即:
    判断当前 “新增行的生效日期” 是否小于等于 “其他行的失效日期”" 且 “新增行的失效日期” 是否大于等于 “其他行的生效日期”
    如果满足,则不允许新增,抛出异常
  2. 倘若用户通过excel导入数据,我们则需要处理这7种时间段的数据。
    我们假设下面的列车是要更新的数据,上面的列车是待更新数据。
    如果是左不相交,则不需要做处理
    如果是左相交,则更新上时间段的失效日期为:下时间段的生效日期-1
    如果是下包含,则删除原时间段及关联数据,新增下时间段
    如果是右相交,则更新上时间段的生效日期为:下时间段的失效日期+1
    如果是右不相交,则不需要做处理
    如果是上包含,则需要将时间段裁成三段,
    第一段为更新上时间段的失效日期为:下时间段的生效日期-1
    新增下时间段
    新增数据:生效日期为下时间段的失效日期+1,失效日期为上时间段的失效日期
    如果是完全重合,删除上时间段,新增下时间段

这是单条时间段更新单条时间段的逻辑,如果是多条更新多条呢?

其实也是相同的逻辑。

我们将原时间段数据从数据库取出,到内存中计算,遍历待新增的时间段和原时间段逐一匹对处理后,内存会生成新的多时间段数据行。for循环中下一行待新增的时间段,将会是和这一新的多时间段数据行逐一匹对。
于是,“多条更新多条” 的逻辑就为:遍历新时间段 + 内循环原时间段 + “单条时间段更新单条时间段”逻辑(复杂度N^2)

本质相同

4. 多维度校验处理

对于录入数据的校验,原始需求为:物料在相同时间段内的供应商比例之和必须为100
对于接收到的需求,我们一般会如何进行代码的编写?

利用hashmap存储数据,key为物料编码+开始时间+结束时间 value为供应商比例之和
最终校验是否所有value都为100

但我们再回顾一遍需求背景,录入的数据是否会存在如下情况:
数据:
物料A 2023.1.1-2023.12.30 供应商A 配额比例100%
物料A 2023.6.1-2024.12.30 供应商B 配额比例100%
对于这样的数据,6.1-12.30时间段内,供应商比例>100,但仍旧可以顺利的通过校验

于是我们需要重新调整需求描述,设计新的解决问题方案。
新方案如下:

方案一:

先校验时间重合性,再校验供应商比例之和
2023.1.1-2023.12.30和2023.6.1-2023.12.30明显存在时间重合,不会通过校验

方案二:

将时间段拆分到“天”的颗粒度,再分别计算每天的供应商比例之和
2023.1.1-2023.12.30会被拆分成365条数据, 2023.6.1-2024.12.30会被拆分成183条数据,再分别计算每天之和
2023.1.1-2023.12.30和2023.6.1-2023.12.30明显存在时间重合,不会通过校验

两方案优劣对比:

方案一优势:

  1. 可以复用时间段重合代码,编写难度低
  2. 校验方案清晰,便于修改

方案一劣势:

  • 对于如下数据,方案一不会通过校验
    物料A 2023.1.1-2023.12.30 供应商A 配额比例50%
    物料A 2023.1.1-2023.05.31 供应商B 配额比例50%
    物料A 2023.6.1-2024.12.30 供应商B 配额比例50%
    由于存在时间段重合,方案一对该数据组不会通过校验

方案二优势:

  1. 可以解决方案二劣势中例举的数据组合
  2. 方案逻辑清晰,代码方案清晰
    方案二的代码方案设计如下:
    将一行数据拆分为“天”颗粒度,同时将拆分后的数据存储至数据库中,并将数据按物料+时间进行排序。在提交校验时,group by物料+时间,计算供应商比例之和是否为100

方案二劣势:

  1. 从方案设计、代码设计中都可以看出,如果客户录入的数据量非常庞大时,我们需要多出至少100、200倍的数据行存储至数据库中。这无疑会指数级得增加表中数据量,且增大内存计算的压力。
并且该方案也存在一个隐藏的逻辑问题:上午客户录入数据至系统中后,发现录入的数据存在错误,需要重新录入。

如:
原数据:物料A 2023.1.1-2023.12.30 供应商A 配额比例100%
修改后:物料A 2023.1.1-2023.06.30 供应商A 配额比例100%
那么此时,数据库中会同时存在由2023.1.1-2023.06.30拆分后的183*2条数据,且该期间内比例之和为200%

可能会有人提出,可以将拆分后的数据存储至另一数据库表中,并在执行成功后及时清理数据。
那么方案二的两个劣势问题都可以解决。
但在实际情况中,存在一个每晚11:55的定时任务,去根据录入的信息去更新其他数据。逻辑大体相同
且倘若客户批量录入的单张表单数据量达到万条,数据量成百倍增长带来的内存计算压力仍旧难以缓解

比较两个方案后,我们认为:

技术是为业务服务的
但适当的业务需求让步,可以避免技术上的过分设计。

选择方案一

总结:多维度校验的逻辑,通常都可以根据具体业务,采用逐个验证的方案解决

5. 补充

问题一:在原方案中用户通过excel导入数据,就不需要处理这7种时间段的数据了么?
回答:需要。在后续中,将项目上的经验进行总结后也修改了平台功能。这就是ToB需要进项目的原因之一吧。

问题二:既然原方案也需要这一逻辑,为什么不在文章分享中,只介绍更新后的原方案逻辑?
回答:因为贪心,想顺带讲一嘴多维度校验处理。

6. 场景设计+代码待更新……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值