new-june

  用过SAP的凭证批量录入模板(Excel文件)的都知道,一个凭证由【抬头】和多个【行项目】组成,这是一个关于excel两表信息关联的典型场景。

  这里头蕴藏着一个麻烦:当我们需要一次性录入多个凭证时,如何将每个凭证的抬头与行项目关联起来呢?

假定这是一个SAP凭证的excel录入模板,包含多个待录入的凭证:

【抬头】表:

号码 凭证日期 凭证类型 公司代码 记账日期 货币 汇率 参考凭证号 抬头文本
1 20220113 RE CN10 20200113 CNY     这是一个仅用于测试的凭证1
2 20220113 RE CN10 20200113 CNY     这是一个仅用于测试的凭证2

 

 

 

 

【行项目】表:

号码 记账码 科目账户 特别总账标识 凭证货币金额 税码 成本中心 订单 文本 基准日 分配 原因代码 贸易伙伴
1 40 1001010000   123.25       这是一个用于测试的凭证1   20210106 A11  
1 19 1066322 A 123.25       这是一个用于测试的凭证1   20210106    
2 40 1001010000   427.86       这是一个用于测试的凭证2   20210108 A11  
2 19 1066323 A 427.86       这是一个用于测试的凭证2   20210108    
                         

 

 

 

 

 

 

 

   看了表结构,如果实际业务中【抬头】文本跟【行项目】文本要求有一定差异,那么能将两张表关联起来的就剩【号码】字段了。此处【抬头】号码1跟【行项目】号码1说的都是第1个待录入凭证。

当我们第一层循环是遍历【抬头】表的每一行时,第二层内循环便是遍历该凭证行项目对应的每一行。进一步分解需求,比如号码1,我们需要动态计算号码1在【行项目】的起始和终止行号。小爬能想到的思路有以下三个。

  ①利用excel公式来动态计算;

  ②利用两个字典分别存储某个号码在【行项目】中的首尾行号;

  ③建立个临时表temp,利用sql或Excel自带筛选功能快速筛选出号码等于特定数字(比如1)的数据,写入临时表。

 

先说方法一:使用match结合countif分别得到首尾行号。

如下图所示:

 

 

接着说说方法二:使用字典来得到某个凭证行项目的首尾行号

  我们从上至下遍历【行项目】每一行,用字典(key,value)分别存储号码和对应的行号,由于字典【key】的唯一性和可覆盖性,我们永远key对应【号码】,则value永远对应的该key最后一次出现的位置(行号),因为该key第一次存入字典的value(起始行号),随着逐行往下遍历,被不停用新的value(行号)覆盖。

此时我们只需要掌握一个trick,先定义个字典,从上至下遍历,最终存储key(号码)和value(结束行号);紧接着再定义个字典,从下至上遍历,便可存储key(号码)和value(起始行号),你get到这一点了吗?

  完整实现的代码示例(VBA)如下:

 1 Sub voucherEntry()
 2 Dim headerSht As Worksheet, itemSht As Worksheet, numberStr As String, startNum As Integer, endNum As Integer, headerMaxRow As Long, itemMaxRow As Long, i As Integer, j As Integer
 3 Dim startDic As Object, endDic As Object
 4 Set startDic = CreateObject("scripting.dictionary")
 5 Set endDic = CreateObject("scripting.dictionary")
 6 
 7 Set headerSht = ThisWorkbook.Sheets("抬头")
 8 Set itemSht = ThisWorkbook.Sheets("行项目")
 9 headerMaxRow = headerSht.Cells(Rows.Count, 1).End(xlUp) \'[抬头]表的最后一行行号
10 itemMaxRow = itemSht.Cells(Rows.Count, 1).End(xlUp) \'[行项目]表的最后一行行号
11 For i = 2 To itemMaxRow
12     endDic.Add CStr(itemSht.Range("A" & i).Value), i \'将号码与对应行号的关系存入字典,思考下,为啥要转为字符串格式
13 Next
14 
15 For i = itemMaxRow To 2 Step -1
16     startDic.Add CStr(itemSht.Range("A" & i).Value), i \'将号码与对应行号的关系存入字典,思考下,为啥要转为字符串格式
17 Next
18 
19 For i = 2 To headerMaxRow \'遍历【抬头】表每一个抬头行
20     numberStr = CStr(headerSht.Range("A" & i).Value) \'【号码】,思考下,为啥要转为字符串格式
21     startNum = startDic(numberStr) \'凭证对应的起始行号
22     endNum = endDic(numberStr) \'凭证对应的结束行号
23     For j = startNum To endNum \'遍历该凭证行项目的每一行
24         此处维护核心【代码块】
25     Next
26 
27 Next
28 
29 End Sub

至于方法三,小爬就暂时不对此进行具体实现了,感兴趣的同学不妨自己动手尝试一波~

 

快来扫码关注我的公众号 获取更多爬虫、数据分析的知识!

分类:

技术点:

相关文章: