2023-11
1

不闪烁的跨表复制

By xrspook @ 8:00:17 归类于: 烂日记

昨天说到当我想用VBA把一个工作簿里面的某些工作表复制到另外一个工作簿的时候,如果要复制的工作表有多个,复制过程中就会出现闪烁。如果需要复制的工作表很多,闪烁的时间会比较长。我觉得批量选择,最后一次性复制是一个解决办法。如果不是用VBA,而是手动实现这个复制功能,的确会用批量选择,然后再复制。现在按住Ctrl,然后用鼠标选择需要复制的工作表,最后进行复制。如果要在VBA里面实现这个批量选择,该怎么做呢?

一个工作簿里的工作表该如何判断哪些是需要的,哪些是不需要的,对我来说只需要判定工作表的名称就可以,所以我可以对需要的工作表以某种方式结合起来,比如形成一个以固定分隔符的字符串。VBA里要表达批量选择,然后复制,到底该用什么东西呢?这一次我没有搜索,而是直接录制了个宏。结果发现原来批量选择再复制,在宏里默认是通过数组的。需要把目标工作表的名称组合成一个一维数组,然后用最普通的复制方式把拷贝到新的工作簿。所以我要做的就是把目标工作表的名称赋值给一个一维数组。因为不知道到底要复制多少个工作表,所以这个数组应该是一个动态数组,我马上想到的方式就是以默认分隔符打断字符串的方式赋值给一维的动态数组。这个操作非常高效,而且动态数组的大小完全不需要在一开始就定义好,字符串里面有多少东西就可以生成多大的一维数组。

接下来,我要做的是经过一轮循环筛选出某个工作簿里我需要的工作表的名称,然后把这些名称以固定分隔符的方式连接起来。最后在打断之前我还要干掉一个分隔符,因为无论我把分隔符放在最前面还是最后面,整个字符串还是会多一个分格符。我不知道多一个分隔符在赋值给一维数组的时候会不会失败,作为完美主义者,我宁愿手动把那个分隔符去掉。那不过是一个字符串取值的简单操作而已。处理好字符串以后,就可以打断那个字符串赋值给一维数组,最后通过经典的复制方式,把工作簿里的目标工作表拷贝到另外一个工作簿。

我没有测试过这样处理耗时跟基础经典处理有多大差别,但就肉眼来说,差别挺大。因为如果进行这般批量选择一次性复制,基本上可以秒杀完成,但如果使用经典的方法、工作表又比较多,我感觉得闪烁一秒钟以上。秒杀就能完成我感觉那个耗时会在0.3秒以内。

批量选择再复制的确可以秒杀实现拷贝工作表,但是光标会停留在最后一个被复制的工作表里,我需要光标仍然停留在我的点击VBA控件的工作表。所以最后我又增加了一个激活目标工作表,把鼠标锁定在某个单元格的功能。这个功能不是非如此不可的,没有也不影响数据处理本身,但就方便程度而言,这是显而易见的。就如没有初始化和拷贝数据那两个模块,核心功能没问题,但是多了这些贴心的小步骤。整个核对的过程会变得更顺手。

如果使用的时候能更顺畅,我宁愿把代码搞得复杂一些。毕竟复杂的代码是一次性的。

PS:测试
复制19个工作表:批量法0.85秒,经典法7.25秒。
复制8个工作表:批量法0.59秒,经典法3.02秒。
复制4个工作表:批量法0.48秒,经典法1.59秒。

Sub 批量拷贝工作表-批量法()
    Application.ScreenUpdating = False '关闭屏幕刷新
    Dim book As Workbook
    Dim sht As Worksheet
    Dim my_name As String, stringArray() As String
 
    my_name = ""
 
    For Each book In Workbooks
        If book.Name <> "AAA.xlsm" Then
            For Each sht In book.Worksheets
                If Not sht.Name Like "*BBB*" Then
                    my_name = my_name & sht.Name & ","
                End If
            Next
            my_name = Mid(my_name, 1, Len(my_name) - 1)
            stringArray = Split(my_name, ",")
            book.Sheets(stringArray).Copy before:=ThisWorkbook.Worksheets("条件")
        End If
    Next
 
    With ThisWorkbook
        .Worksheets("条件").Activate
        .Worksheets("条件").Range("A27").Select
    End With
 
    MsgBox "完成数据抓取!"
    Application.ScreenUpdating = True '打开屏幕刷新
End Sub
 
************************************
 
Sub 批量拷贝工作表-经典法()
    Application.ScreenUpdating = False '关闭屏幕刷新
 
    Dim book As Workbook
    Dim sht As Worksheet
    For Each book In Workbooks
        If book.Name <> "AAA.xlsm" Then
            For Each sht In book.Worksheets
                If Not sht.Name Like "*BBB*" Then
                    sht.Copy before:=ThisWorkbook.Worksheets("条件")
                End If
            Next
        End If
    Next
 
    With ThisWorkbook
        .Worksheets("条件").Activate
        .Worksheets("条件").Range("A27").Select
    End With
 
    MsgBox "完成数据抓取!"
    Application.ScreenUpdating = True '打开屏幕刷新
End Sub
2023-10
31

老脚本加新模块

By xrspook @ 10:52:25 归类于: 烂日记

几年以后,我终于又在某一个我用来核对账本的VBA脚本上加了两个新的模块。之前这两个模块的内容我都是手动实现的。第一个模块是初始化,就是把已经核对过的明细数据删除掉。初始化这个步骤眨眼间就完成了,因为是在同一个工作簿里进行。另外一个模块做的是数据抓取,抓取我需要核对的那个工作簿里的明细工作表。我要核对的那个工作簿里的汇总,那个工作表默认不抓取,因为那是用来核对的。另外一个跟明细数据和汇总数据不是一伙的工作表也不能抓取,因为那个表的数据格式跟其它的不一样。过去这几年来我做的事情都是手动的在VBA脚本所在的工作簿里删除掉已核对的数据明细,然后再把我需要核对的那个工作簿里的明细粘贴到VBA脚本所在的工作簿。这个操作很机械很单一,完全可以用VBA去实现,但是我却一直没有这么干,为什么呢?大概是因为最初的时候,我写的那个VBA脚本核心部分实现的功能已经减少了我绝大部分的工作量,简单实现了非常麻烦才能实现的事情,所以我觉得自己已经上岸了,相对来说,这些复制粘贴删除的东西比较简单。简单归简单,很容易能实现,但是日积月累经常性习惯性每一次都要整那么十几二十遍也是很烦的。为了简化初始化的那个步骤,我每次核对完就以不保存的方式关闭VBA脚本所在的工作簿,然后重新打开。

我不知道对以前的我来说,写着两个模块有多难,对现在的我来说,对今年已经在VBA脚本里浸润了好几个月的我来说挺简单。实现方法很简单,但是出来的效果我感觉上应该还可以改进。初始化的那个脚本已经很完美,没啥需要再进一步了,但是那个拷贝数据的脚本,如果需要复制的工作表有很多,屏幕会出现长时间的闪烁。那种闪烁源于不同工作簿之间切换导致聚焦位置改变。之所以这样,因为我所使用的复制方式是VBA教程里最简单的那款。微软的默认教程就是那样,当然你也可以使用不一般的方式。闪烁是因为不同工作表之间切换以及活动工作表活动单元格之间的变换。这个问题之前我已经发现。我以前的VBA脚本里也有这种问题。做一个循环,把某个工作表名称符合要求的就复制到 VBA所在的工作簿,这个循环是显而易见的,但是一个一个工作表去判断,一个一个复制显然就会出现很多次闪烁。如果我先去判断,然后把符合要求的全部选定,最后一次性复制,这样会不会就可以从多次闪烁变成一次闪烁呢?多次闪烁你肯定能感觉到闪烁的存在,但如果只是一次,估计那种闪烁感就会感知不到了。有人在网上提出过如何避免闪烁这个问题,但好像大家都没有在批量选择然后一次性复制上面想。我也想参考他们的做法改进,但好像不太适合我的实际情况。

我觉得闪烁这个问题是可以攻克的。

2023-10
1

9月挺过去了

By xrspook @ 10:48:02 归类于: 烂日记

已经放了两天的假,但是这两天我依然不得不跟工作有紧密联系。9月30里的晚上,从8点多开始我就在忙工作,虽然其实单位的业务是9点多才结束的,但是能干的那些我都已经先干了,但其实我又没有全部干完,但即便这样的话,还是干到了晚上11点多。之所以没干完,并不是因为我差那么点时间,而是我觉得我得主动变得不那么主动,因为我把别人的事情都干完了,别人就不知道干什么好了。所以没干完那些事是我故意留下来的。但实际上把那些事干完才算是一个完整的闭合,能保证数据准确。

这个月末是我第一次用某个VBA的脚本自动给我粘贴那些量不少,但是没什么营养的东西,起码对我来说是没什么营养的,但是上面就是需要用某种格式输出让他们看到。过去几年我都是人肉进行格式的转换,然后人肉进行复制粘贴,上个月末我来不及做出来,但是思路已经有,所以在月头的时候我就已经把这个做了出来,试过没有问题,但我不确定使用的时候会不会还有bug,结果如我所料,的确是有bug的,其中一个包非常的无语,是复制粘贴没对上位,为什么测试的时候没有看出这个问题我也不知道。另外一个不能说是我的bug,因为数据太小了,如果是四舍五入保留三位小数,那个数在三位小数以外,所以就被零处理了,但实际上那不是0。最后一个bug,其实之前我也遇到过,那是一个关于替换时选择关键词的东西,在什么时候替换?关键词是什么?如果用一般的思路去考虑,就是那样,但实际上选择那样的关键词不准确,所以最终替换出来的不是我想要的东西。

总的来说,这三个bug虽然存在,但要纠正过来还是比较容易的。对我这个写脚本的人来说肯定是容易的,因为我知道那个思路是什么,虽然已经隔了一个月,具体不再那么清楚了,但是我还在我还是很清楚当时自己用的大概是什么样的方案。如果这个第一次不是让我遇到了,而是别人遇到了,这样的bug,可能就比较郁闷,最终就可能只能用回我以前的老方式,人肉去做复制粘贴和数据汇总。

8月我花了很多时间写VBA,9月份我花了大概一周的时间做统计分析,然后又花了一周多的时间去学习《深入浅出统计学》,然后接下来就进入了疯狂的月末。因为同事出去学习了一周,9月的最后一周又是跟中秋国庆假期关联的,同事提前两天请假回家了,所以我感觉后半个月好像有很多事,好像一直都很忙,实际上也的确这样,因为单位的业务仿佛进入了疯狂的高铁模式,而且是悬浮列车的那种。几乎可以这么说,完全突破了我的想象力,无论是车还是船,作业的数量都是让我觉得是空前的。为什么一天居然可以整那么多车?为什么装的那些船永远都装不完?每天作业的仓号最多的那天有19个。明明某个客户一天就只出那么几千吨,但是每天都起码有5个以上的仓房在进出。每个客户一个仓房,但是有很多个客户,又或者只有几个客户,但每个客户都动很多个厂房,这两种情况都会让我抓狂。因为这意味着明明作业量不大,但需要做很多个汇总数据。

但总算这个9月我挺过去了。

2023-09
2

选择关键词

By xrspook @ 10:39:32 归类于: 烂日记

写VBA的这段日子,我觉得自己的脑子越来越习惯用那种方式思考。如果你要把一件经常做的事情程序化,你就得抓住一些关键点。虽然流程大概差不多都那样的,但实际上人在操作的过程中还是有一些关键。如果想把那些流程标准化、自动解决问题,你就得把那些模糊的关键点全部都明确,比如看到什么关键词进行什么操作,这得一清二楚,而且这些关键词的选择还得考虑不容易被干扰。这些关键词的选取对一般人来说是没什么概念的,他们觉得大概应该那样,但实际上你要在一堆东西里面选取关键词,绝对不能像在一些标准序列里面选其中一个那么自然。

有一天同事发微信过来说我上报的某个数据好像不对,因为他筛选出来的结果不是那样的。我不知道为什么会发生这种事情,因为在上报那个数据之前,我已经再三核对。又过了一段时间,他又发微信过来告诉我,是他筛选的时候出现了一些干扰项,之前他没看到。他在去向字段筛选的关键词是Q3,理论上那是一个仓号,对绝大多数人来说,如果只说这两个字,也会觉得这是一个仓号,但问题是那天刚好遇到某个车的车牌里有这个Q3这两个字,于是他筛选到的结果跟我计算Q3的数量当然就有区别了。这个时候,如果他筛选的关键词不是Q3,不是Q3-01就不会有这种问题,因为没有一个车牌会有“-”。如果他选的是Q3-01,那么那些Q31、Q35的仓号也不会干扰到他的筛选结果。我不知道浪潮那些筛选项是如何设置的。如果是以前的那个系统,以前的那个需要运行exe的系统筛选,你还得选择到底是什么形式的筛选,是等于大于还是包含。现在浪潮那个在网页上运行的系统筛选词就只是模糊匹配。如果去向那里必须精确匹配,你不写Q3-01就返回不到你要的结果,他也不会遇到车牌号这种事情。把车牌和仓号按照流向放在来源和去向,从一开始我就觉得这很逆天。如果一开始就给我这样的数据,最后我还得通过入库和出库去判定到底哪个是车,哪个是仓。如果我的同事查找数据的那个界面没有这种来源和去向,只有流向、仓号、车船号,显然他一定会在仓号那里选Q3,而不会去车船号那里输入Q3,这样的话也不会遇到他碰到过的问题。

对编程的人来说,尤其是对那些专门要把某些程序自动化的人来说,非常在乎关键词的选择。因为把一些老表格自动化的过程中你会发现那些东西根本不是标准的字段模式。要怎么把那些非标的东西标准化,你就得绞尽脑汁选择关键词,怎么才会不重复?怎么才能实现你的目的?当然了,之所以这么说是因这些标准化是基于Excel工作表的,如果那本来就是一个数据库里面的东西,即便他们不愿意标准化,有些东西也不得不标准化。

当你强迫自己以某种方式去思考以后,经过一段时间的锻炼,你会觉得自己在不知不觉之中有了那种条件反射的能力。

2023-09
1

小心很失望

By xrspook @ 11:03:32 归类于: 烂日记

当我正在潜心研究VBA+ADO+SQL的时候,某一天当我去搜索某个问题的解决方案,发现Excel里将要内置python了。那这个到底是什么样的python呢?星期四的晚上我看到ExcelHome的专业人士进行了进一步的解释。他们的专业人士说的东西,我还是比较认可的。

当我第一次听说Excel里面终于可以用python的时候,我并不太兴奋。为什么会这么说呢?因为是在Excel的某个地方写python,而不是在一个完备的IDE里写。这有什么问题呢?

可以这么说,Excel所有写代码的地方都让人挺不愉快。比如你要写公式,经常的情况是你选了那个,一会车,然后就没有了。如果你要写嵌套的公式,那些括号更加是会把你搞死。写公式的那个地方,你很难分得清全角和半角标点符号,于是你经常被卡在那个地方,然后被卡没了才发现自己在打勾之前没有先复制粘贴到其他地方,所以打那一大堆全部白费了。

在其它编辑器里也很郁闷。PQ有高级编辑器,高级编辑器好像要比公式智能一点点,但是又过于智能了,比如经常会帮助你自动添加一些符号,有可能是双引号,更多时候是逗号或者括号,但那并不是你想要的,你自己会把那补全。在你不知情的情况下,PQ给你添加上去以后,最终就报错了,翻找一大堆后才发现,那里不知道为什么多了一个符号。

PP里面写公式,如果是写度量值,情况还会好一点,因为你可以先做一个公式的校验,校验失败起码就意味着你基本上不用确定提交了,但是校验的时候到底是哪里不对,为什么不对呢?这得凭借你的经验。如果你进入到PP里面,在那个类似于Excel写公式的那个地方写代码,经常遇到的情况是你还没写完,就直接给你报错。因为报错了,你被卡住了,所以还真的漏了一些东西,结果当然是无果了。

相对于PQ和PP来说,VBA算是Excel里面可以写代码比较完善的地方。在VBA里有标识符和关键字,而且可以设置不一样的颜色,但问题是VBA那个编辑器除了会帮你增加空格以外,你别想能帮你进行任何的补全。无论函数名称还是那些你之前已经定义过的变量。被大家吐槽的最多的是一句判断没写完,要到其它地方复制东西,马上弹窗告诉你语法错误。当你运行不通过的时候,会有各种各样的弹窗,但绝大多数情况之下提示都没什么意义,因为没有针对性,你不知道该怎么改。

综上所述,在现有的Excel里面写代码,除非你非常牛逼,一写就对,万一你是那种粗心大意到极点的人,在Excel里写代码会让你非常崩溃。那个大家期待已久的python,据专业人士说,输入的方式是盲打。你别想Excel会给你补全,会给你提示任何错误。而且那个python in Excel是云上的东西,所以你的电脑上可以完全不安装python,数据通过网络云计算然后再返回结果。这就意味着算力最大的障碍就是你和服务器之间到底有多通畅?VBA完全可以脱机使用,那就意味着可以秒杀出结果,但如果我用的是python,需要实现同样的功能,我跟云服务器那边用有几万光年的代沟,甚至根本连不上,那么python那个地方永远都会显示#BUSY#,永远都不会有结果。如果一直挂在那里,或者某一时刻终于连上了,就会把结果反馈回来。我从来不太相信微软的服务器,因为从windows或者office软件系列的更新就可以看出,我们跟微软的服务器有非常深的代沟。现在这个刚刚有了雏形的python,居然是暂时只能用云计算,这样的东西能让人有多少期待呢?如果你不是在中国,如果你在美国,你是一个Microsoft 365的付费用户,而且是专业版的。可能会好很多,但是,我们在中国,我只能说希望越大失望越大。

我还是用好手头上的工具,实现我的小目标好了。

© 2004 - 2024 我的天 | Theme by xrspook | Power by WordPress