Excel·VBA自动生成日记账的对方科目
如图:根据日记账/序时账的日期、凭证号为一组,按借贷方向生成相反的科目,并写入H列。可能存在一对一、一对多、多对多等情况的账目
目录
- 数组法遍历、判断、写入
- 测试结果
- 多对多问题处理
- 测试结果
数组法遍历、判断、写入
适用日期凭证号连续的日记账
按照判断难易程度从简单开始,先判断科目一对一的同向/反向情况;再判断科目一对多且借方和贷方数组剩余数据刚好相等的情况;最后再判断多对多的情况,由于多对多可能涉及组合求和问题,耗时会比较长,因此以下代码删除了多对多的情况,另写一个sub专门处理多对多问题。(数据匹配后,对应的数组该数据会清空,方便后续判断)
Sub 生成对方科目_一对多()'适用日期凭证号连续的日记账,一对多版;start_end(1)限制代码运行结束行数Dim arr, d, e, f, res, i&, j&, x&, m, brr, b, write_col$, s$, ss$, s1$, s2$tm = Timer: write_col = "h" '结果写入列号start_end = Array(2, 0) '开始结束行号With ActiveSheetarr = .[a1].CurrentRegionIf start_end(1) = 0 Then start_end(1) = UBound(arr) '结束行号默认最后一行DoReDim d(1 To 100): ReDim e(1 To 100): ReDim f(1 To 100)s = arr(start_end(0), 1) & arr(start_end(0), 2): x = 0For i = start_end(0) To UBound(arr)ss = arr(i, 1) & arr(i, 2)If s = ss Then x = x + 1: d(x) = arr(i, 4): e(x) = arr(i, 5): f(x) = arr(i, 6)If s <> ss Or i = UBound(arr) ThenReDim Preserve d(1 To x): ReDim Preserve e(1 To x): ReDim Preserve f(1 To x)ReDim res(1 To x): Exit ForEnd IfNext'金额判断科目For t = 1 To 2 '执行2次循环,尽可能多配对len_e = Len(Join(e, "")): len_f = Len(Join(f, ""))If len_e Or len_f Then '不为空数组For i = 1 To x '一对一,一对多If Len(e(i)) Then '一借一贷m = Application.Match(e(i), f, 0)If TypeName(m) <> "Error" Then res(i) = res(i) & "," & d(m): res(m) = res(m) & "," & d(i): e(i) = "": f(m) = ""End IfIf Len(f(i)) Then '一借一贷m = Application.Match(f(i), e, 0)If TypeName(m) <> "Error" Then res(i) = res(i) & "," & d(m): res(m) = res(m) & "," & d(i): f(i) = "": e(m) = ""End IfIf Len(e(i)) Then '借方一正一负m = Application.Match(-e(i), e, 0)If TypeName(m) <> "Error" Then res(i) = res(i) & "," & d(m): res(m) = res(m) & "," & d(i): e(i) = "": e(m) = ""End IfIf Len(f(i)) Then '贷方一正一负m = Application.Match(-f(i), f, 0)If TypeName(m) <> "Error" Then res(i) = res(i) & "," & d(m): res(m) = res(m) & "," & d(i): f(i) = "": f(m) = ""End IfIf Len(e(i)) Then '一借多贷,剩余金额相等;计算精度问题ts = WorksheetFunction.sum(f)If e(i) = ts Or Abs(Round(e(i) - ts, 6)) < (0.1 ^ 6) ThenFor j = 1 To xIf Len(f(j)) Then res(i) = res(i) & "," & d(j): res(j) = res(j) & "," & d(i): e(i) = "": f(j) = ""NextEnd IfEnd IfIf Len(f(i)) Then '多借一贷,剩余金额相等ts = WorksheetFunction.sum(e)If f(i) = ts Or Abs(Round(f(i) - ts, 6)) < (0.1 ^ 6) ThenFor j = 1 To xIf Len(e(j)) Then res(i) = res(i) & "," & d(j): res(j) = res(j) & "," & d(i): f(i) = "": e(j) = ""NextEnd IfEnd IfNextIf len_e = 0 And Abs(WorksheetFunction.sum(f)) < (0.1 ^ 6) Thens1 = "": s2 = "" '借方为空,贷方和为0,多正多负For tt = 1 To 2 '第1遍读取数据,第2遍写入数据For i = 1 To xIf Len(f(i)) And f(i) > 0 ThenIf tt = 1 Then s1 = s1 & "," & d(i)If tt = 2 Then res(i) = s2: f(i) = ""ElseIf Len(f(i)) And f(i) < 0 ThenIf tt = 1 Then s2 = s2 & "," & d(i)If tt = 2 Then res(i) = s1: f(i) = ""End IfNextNextElseIf len_f = 0 And Abs(WorksheetFunction.sum(e)) < (0.1 ^ 6) Thens1 = "": s2 = "" '贷方为空,借方和为0,多正多负For tt = 1 To 2 '第1遍读取数据,第2遍写入数据For i = 1 To xIf Len(e(i)) And e(i) > 0 ThenIf tt = 1 Then s1 = s1 & "," & d(i)If tt = 2 Then res(i) = s2: e(i) = ""ElseIf Len(e(i)) And e(i) < 0 ThenIf tt = 1 Then s2 = s2 & "," & d(i)If tt = 2 Then res(i) = s1: e(i) = ""End IfNextNextEnd IfEnd IfNextFor i = 1 To x '清除开头的","If Len(res(i)) Then res(i) = Mid(res(i), 2)Next.Cells(start_end(0), write_col).Resize(x, 1) = WorksheetFunction.Transpose(res)start_end(0) = start_end(0) + xLoop Until start_end(0) > UBound(arr) Or start_end(0) > start_end(1)End WithDebug.Print "用时:" & Format(Timer - tm, "0.00") '耗时
End Sub
测试结果
在15248行日记账中,生成了12858行的对方科目,用时0.59秒
可以处理科目一对一、一对多的情况,以及同方向的多对多和为0的情况(如图)
多对多问题处理
考虑到多对多问题,涉及组合求和问题,耗时会比较长,因此 start_end(1) 参数控制代码运行行数。且不修改一对多版生成结果
组合求和问题调用了combin_arr1函数,代码详见《Excel·VBA数组组合函数、组合求和》(如需使用代码需复制)
Sub 生成对方科目_多对多()'适用日期凭证号连续的日记账,多对多版;start_end(1)限制代码运行结束行数;不修改一对多版生成结果Dim arr, d, e, f, res, i&, j&, x&, m, brr, b, write_col$tm = Timer: write_col = "h" '结果写入列号start_end = Array(2, 0) '开始结束行号With ActiveSheetarr = .[a1].CurrentRegionIf start_end(1) = 0 Then start_end(1) = UBound(arr) '结束行号默认最后一行hrr = .Cells(1, write_col).Resize(UBound(arr), 1) 'h列数据DoFor i = start_end(0) To UBound(arr) 'h列为空If Len(hrr(i, 1)) = 0 Then start_end(0) = i: Exit ForNextReDim d(1 To 100): ReDim e(1 To 100): ReDim f(1 To 100): ReDim res(1 To 100)s = arr(start_end(0), 1) & arr(start_end(0), 2): x = 0For i = start_end(0) To UBound(arr)ss = arr(i, 1) & arr(i, 2)If s = ss Thenx = x + 1If Len(hrr(i, 1)) = 0 Then 'h列为空d(x) = arr(i, 4): e(x) = arr(i, 5): f(x) = arr(i, 6)Elseres(x) = "," & hrr(i, 1) '不修改原版生成结果End IfEnd IfIf s <> ss Or i = UBound(arr) ThenReDim Preserve d(1 To x): ReDim Preserve e(1 To x): ReDim Preserve f(1 To x)ReDim Preserve res(1 To x): Exit ForEnd IfNext'金额判断科目For i = 1 To x '一借一贷,一对多If x > 20 Then Debug.Print "数据太多,求和速度慢": Exit ForIf Len(e(i)) Then '一借一贷,一对多For j = x - 1 To 2 Step -1brr = combin_arr1(f, j) '调用函数返回组合,一维嵌套数组For Each b In brrtemp_sum = WorksheetFunction.sum(b)If temp_sum = e(i) ThenFor Each bb In bIf Len(bb) Thenm = Application.Match(bb, f, 0)res(i) = res(i) & "," & d(m): res(m) = res(m) & "," & d(i): f(m) = ""End IfNexte(i) = "": Exit ForEnd IfNextIf e(i) = "" Then Exit ForNextEnd IfIf Len(f(i)) Then '一借一贷,一对多For j = x - 1 To 2 Step -1brr = combin_arr1(e, j)For Each b In brrtemp_sum = WorksheetFunction.sum(b)If temp_sum = f(i) ThenFor Each bb In bIf Len(bb) Thenm = Application.Match(bb, e, 0)res(i) = res(i) & "," & d(m): res(m) = res(m) & "," & d(i): e(m) = ""End IfNextf(i) = "": Exit ForEnd IfNextIf f(i) = "" Then Exit ForNextEnd IfNextIf Len(Join(e, ",")) >= x Or Len(Join(f, ",")) >= x ThenFor i = 1 To x '多借多贷,无法组合求和If Len(e(i)) ThenFor j = 1 To xIf Len(f(j)) Then res(i) = res(i) & "," & d(j): res(j) = res(j) & "," & d(i)NextEnd IfNextEnd IfFor i = 1 To x '清除开头的","If Len(res(i)) Then res(i) = Mid(res(i), 2)Next.Cells(start_end(0), write_col).Resize(x, 1) = WorksheetFunction.Transpose(res)start_end(0) = start_end(0) + xLoop Until start_end(0) > UBound(arr) Or start_end(0) > start_end(1)End WithDebug.Print "用时:" & Format(Timer - tm, "0.00") '耗时
End Sub
测试结果
由于耗时较长,仅部分测试
多对多组合问题
多对多非组合问题
存在问题
从特殊情况可知,多对多问题一方数据量较大时,耗时增长明显;而数据量在10以内时,即便需要组合求和耗时也很少,因此编写代码时可以考虑优先处理数据量较小的部分,跳过数据量较多的部分
扩展阅读
《excelhome-如何通过VBA自动生成对方科目》
Excel·VBA自动生成日记账的对方科目相关推荐
- Excel VBA: 自动生成巡检报表并通过邮件定时发送
目录 环境说明 逻辑结构 效果说明及截图 ①. 安装SecureCRT ②. 自动巡检脚本 ③. 数据检索并FTP传送 ④. 安装Excel 2013 ⑤. 安装Serv-U ⑥. 自动生成图表并邮件 ...
- Excel VBA自动生成本年度节假日及补假
利用了百度的opendata API接口,接口链接如下: https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query=2019&r ...
- Excel VBA 自动添加新行并递增ID
Excel VBA 自动添加新行并递增ID 用Excel 2010的VBA功能来处理数据,主要根据IP网段和网段IP个数,来生成每个IP地址,并进行ID编号. Sub AutoInsert()Line ...
- 使用java通过固定的excel模板自动生成数据库表的ddl建表语句
有时候要建很多表或一个表有很多字段,一个个复制字段弄太麻烦了,为了提高点工作效率,写了个小工具通过固定的excel模板自动生成基础的ddl建表语句 maven依赖 <!--核心jar包--> ...
- 表格 自动生成流程图 python_Visio竟然可以根据Excel数据自动生成流程图,这也太牛了吧!...
前段时间受邀去到一家制造型企业培训Excel,在课前沟通的阶段,客户提出一个需求,希望在课程中能介绍一下如何在Excel中绘制流程图.虽然Excel是一个功能非常强大的数据分析工具,但它也不是一个万金 ...
- Excel·VBA模板生成文件
不同于<python实现Excel邮件合并>,字符串内容替换生成文件,仅复制整行数据插入模板中生成工作表,单独保存为工作簿,但如果存在同名工作簿文件,则将工作表附加在该工作簿中 Sub 模 ...
- Excel用vba自动生成word
Sub GenDocfromExcel()'excel控制word,生成新文件,插入图片和文件名,保存 'office 2003, VBA工具/引用中要勾选Microsoft Word 11.0 Ob ...
- VBA自动生成excel的表单及链接的方法
自动生成表单 Sub generateMenu()Dim stCol As Integer, stRow As IntegermenuName = InputBox("MenuSheetNa ...
- Excel VBA | 自动添加序列号
提示:程序代码是根据实际工作的需求编写的,仅供参考学习使用. 文章目录 一.需要实现的功能 :自动添加序列号 二.程序代码 程序代码(一) 程序代码(二) 一.需要实现的功能 :自动添加序列号 操作软 ...
最新文章
- Centos 修改时间地区及NTP同步北京时间
- 挑战马斯克的Neuralink,另一家神秘的「脑机接口」公司已获投资
- 数据表记录包含表索引和数值,请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出。...
- python手把手入门_新手必看:手把手教你入门 Python
- ASP.NET的MVC中使用Session做身份验证(附代码下载)
- c# Ftp下载程序源代码解析
- mysql怎么约束_MySQL 约束详解
- HTML元素(标签)大全及使用说明 (整)
- 温伯格《技术领导之路》——如何弯腰更省力,怎样伸手更合理
- fisco bcos 区块链配置文件位置
- 计算机主机重装主机过程,电脑怎么重装系统步骤 超简单的电脑重装系统教程...
- Kod – 程序员专用编辑器[Mac]
- 基于ARM开发板的嵌入式项目设计(C完整代码)
- 如何创建Roadmap产品路线图
- 如何将两张图片上下合成一张?
- oracle 如何考试,oracle考试怎么报名
- 控制台安装mysql步骤_mysql5.6安装步骤-win7系统
- 甘肃环讯信息科技有限公司加入openGauss社区
- 静默活体检测-人脸活体识别
- Imatest图像处理软件 Imatest Master