好吧,我确实不知道该怎么起这个标题,整了一个“分布”,感觉还有点高档,其实没啥技术含量,看完你就知道了。情况是这样,刚刚接到一个临时任务,需要让几个营业点的销售数据【变】少一点,就是在ERP的相关报表中,查询出来的数据要在指定区间,说白了就是那什么~你懂的,某些同行应该对这种任务很熟悉了,而有些同行可能正在或即将面临这样的任务,希望此文能提供一点思路。
我是第一次接到这种任务,感觉蛮新鲜,思量一下,决定在测试库动手脚,完了让他的ERP接入测试库,事情过后再切回正式库,细枝末节就不说了,重点说一下数据处理方法。根本原理是删除部分单据,因为报表的数据是从单据来的,单据少了,自然数字就小了(至于单据数据结构,不同的ERP方案当然有不同的设计,删除一张单涉及的数据修改也不同,我的情况是直接删除主单就行,细表会自动级联删除,当然还有别的关联数据,那个不用管,反正是测试库,咋折腾都行,只要让报表呈现符合预期就好)。为了让明细数据显得更自然,当然不能简单粗暴的把一段连续时期内的单据统统删除,或者把大量单据的折扣改低以符合目标,那样太粗暴,弄巧成拙就不好了。
我设想的是,按一定时间粒度(如日、周、月、季度)划分单据,然后从每个区间内查出一定比例的单据,然后与目标比对,根据比对情况逐步调整粒度与比例,直至符合目标为止。这样就得到了需要保留的单据,剩下就是把查询区间内的其余单据删除即可。当然也可以将当前数据与目标数据相减,得到需要砍掉的数据,完了以该数据作为目标来查询单据,这样就能直接得到需要删除的单据。我采用的是前一种,即得到需要保留的单据,完了也就一个where not in的事,不费力。上代码:
WITH cte AS ( --按一定时间粒度分组(日、周、月、季度等)SELECT ROW_NUMBER() OVER(PARTITION BY DATEPART(week, 单据日期) ORDER BY 单据编号) AS 'RowNo',DATEPART(week, 单据日期) AS 'Rang', 单据日期, 单据编号, 成交金额FROM 主单表WHERE 营业点='xxx'AND YEAR(单据日期)=2015),cte2 AS ( --得到每组的单据数,作为分母SELECT Rang,COUNT(1) AS 'BillCount' FROM cte GROUP BY Rang)SELECT a.*,BillCountFROM cte aJOIN cte2 b ON b.Rang = a.RangWHERE RowNo/CAST(BillCount AS DECIMAL(16,4)) < 0.81 --按比例取每组的部分行,billcount是int,需转换为小数再除
时间粒度就修改datepart函数的第1个参数(day/week/month/quarter等),注意有2处,比例就修改最后那个0.81,很简单,说一下都多余。
我的环境是SQL08R2,如果有更正确的姿势,还望大侠提点,感谢。
- 1楼剑走江湖
- 还有个建议,针对报表数据表增加周月季度年这几个时间粒度的字段,其字段值通过报表的创建或生成时间来生产各个时间粒度的。当然有了字段你也可以创建索引的。使用空间换时间的方式来实现的按不同时间粒度区间会总聚合所需数据。
- Re: ahdung
- @剑走江湖,感谢支招,您说的是数据挖掘方面的东西吗?我水平有限,还看不懂你说的~囧,等机缘巧合再参悟其中妙处。