普通视图

发现新文章,点击刷新页面。
昨天以前首页

升级VBA抓取方案

作者 xrspook
2024年9月14日 19:26

当年今日

无论是SQL方案还是数据透视表方案,我都是用4个类似的脚本,一款做出来了以后,调整部分的内容,生成其它三款,所以一开始的时候抓取数据我有4个宏,其实里面的内容大多相同。汇总数据,我也有4个宏,SQL有4个,数据透视表也有4个。因为SQL跟数据透视表作用是相同的,所以它们分别搭配4个抓取数据的宏各自组成两个文件。就实现功能来说,这两个文件从形成的那一刻起,已经可以起作用,但是我能不能更进一步呢?

数据抓取用的是最基本的VBA,就只是把数据区域选了一下,然后去掉表头,最后搭配我想要的表头输出。我没有在那个地方就进行筛选,因为之前已经说过,VBA自带的AutoFilter功能不太好用。一开始我没想过要用数据透视表,如果到了SQL,一句where可以把正向的反向的或的且的,想怎么加就怎么加,只是一句话的事情而已。既然在一开始数据抓取单元格层面那么难做筛选,那么我到SQL里做筛选就可以了。后来,因为我又做了数据透视表方案,数据透视表方案可以对字段进行筛选,但关键是如果我抓取了那个数据里面不含有我要排除的内容,又或者我抓取的数据全部字段都要被排除掉,无论是哪一款,都会出错,所以如果用同样的抓取方式,到了数据透视表的那个宏里面,我就需要进行复杂的循环和判断。嵌套一层又一层的公式,再加一层又一层的判断。虽然也能实现我想要的东西,但那样做很麻烦。在做出数据透视表方案的那天晚上,我就在想,在一开始的抓取的宏里面,我能不能直接把筛选这个步骤给做了呢?

要在数组里面进行数据筛选,想想都知道肯定可以实现,但是我想到需要嵌套那些数字就觉得很烦,所以我就翻出了多年以前我用来合并某些数据表的宏。在那里我发现自己用的是把全部数据都粘贴到一起,然后做一个行的删除。当时做的行删除很简单,只要匹配一个字段就行了,我现在的行删除,需要匹配的字段可能会有很多,所以我就把那些需要删除的字段都先放在一个数组里面,然后再利用之前那一天从网上抄回来的那招Application.match方案。在一句if里面就能实现查找某个元素在不在某个数组里,如果在的话就把行删掉。之前写的那个宏的确就这么简单,因为需要删掉的那个部分隔好多行才会出现一次。现在我需要处理的那些数据,说不准我需要删掉的那些行是隔一些才出现,还是下一个就又得删掉,所以在删掉之后,我又赶紧做了一个减法操作,让程序重新测试那一行到底需不需要删除。

在一开始数据抓取阶段,我就把数据范围确定了,把需要例外的数据全部删除,所以后面的SQL跟数据透视表我就可以轻松地直接进行操作,尤其是数据透视表,操作变得简单明了。

因为一开始我不是大神,我只能摸着石头过河,逐渐的磨练自己。

VBA里搞数据透视表

作者 xrspook
2024年9月13日 08:17

当年今日

因为我知道我要实现的那个功能,SQL可以做,数据透视表也可以做。就写代码的熟练程度来说,SQL我肯定更熟悉,VBA的数据透视表有很多参数,我搞不懂到底是什么,反正要实现那个功能,通常是录制一个宏,然后看着办,有需要的数据保留下来,不需要的数据直接删掉。录制的宏通常都很啰嗦,里面有非常多没有必要存在的东西。在不了解数据透视表在VBA里的参数的前提下,先进行一个录制显然是比较靠谱的步骤。但有些东西靠录制是录制不出来的,比如某些字段我需要进行筛选,我只知道有些东西是不能出现的,但我没办法确定可以出现的是什么,所以那一堆不能出现的东西都是反参数。在录制宏的时候,你只能看到什么就反选什么,但关键是这个数据源跟那个数据源的那些参数是不一样的。不一样我只能设定一堆反参数,只要它们是其中一个,就不能显示,但实际上这样的反参数让VBA的数据透视默认不出现你就得兜一个大圈,套上好几层公式实现。最终,在我调试的时候发现的确那些嵌套的公式能把那些反参数都排除在外,但如果数据源里所有数据都是反参数的一部分,那么就会报错,于是我又得在外面加一层捕捉错误的判断。真的是非常折腾。为什么之前我考虑的是SQL而不是数据透视表,反参数是其中一个点,另外一个点是排序。在SQL里,使用自定义序列排序是非常简单的事情,但是数据透视表的字段该如何排序呢?兜了一大圈我发现也就只能真的在Excel里面增加自定义序列,但如果我想用即弃呢,于是还得出了一招VBA先增加自定义序列,排序完以后再把自定义序列删除掉。这个操作在ExcelHome的教程里有,他们教的是在VBA里面,对单元格或者数组排序,不是针对数据透视表的,但实际上原理一样。

这个增自定义序列和减自定义序列到底是怎么确认呢?原来Excel还会对自定义序列给一个序号,所以在增自定义序列的时候,你就得把这个序号记下来,在减的时候把那个序号写上去。我不知道为什么其他人说数据透视表的自定义序列好像怎么排都不是自己想要的效果,但就我个人的经验来说,只要你在Excel里增加了自定义序列,当你刷新数据,默认对某个已经自定义过的字段进行升序,那就是你定义的那个顺序,不需要在设置里面搞一大通。但实际上我也搞不懂,手动设置里很麻烦的东西到底是什么。为什么数据透视表里面的排序就不能像普通表格排序那样那么的直观。我要以什么字段排序、以什么标准排序是系统默认的还是自定义序列。当然,数据透视表里还得考虑一个问题,就是有可能是套叠了多个汇总条件的,如果你自定义的是最后一层条件,首先限制你的是前面的那些所有条件,所以你想最后的那个自定义序列完全按照你的想法排列,你只能把它放到最前面。数据透视表跟SQL比起来,我感觉运行速度会慢一点,可能因为我里面判断设置的东西比较多,所以需要闪那么一下才能结束,但是SQL虽然我已经有意识地关注结尾这个问题,但测试频繁以后,SQL是会出现一些莫名其妙的事故,当你把所有东西关掉再打开就正常了。相比之下,数据透视表不会这么神经。

用不同的方法实现同样的事情,得出一样的结果,这种感觉很好。在探索这个的过程中,会让我体会到二者的优劣,以后选择的时候,我就可以更有底气地数出1234。

VBA里奇怪的筛选与粘贴

作者 xrspook
2024年9月11日 09:05

当年今日

上周五我尝试纯粹用VBA的方式对某些数据先进行筛选,然后保留在粘贴板,又或者是把那些东西输出。前提是对某些数据进行筛选复制的时候,我首先必须得有个条件。理想很完美,现实很骨感。

VBA本身就自带一个叫做autofilter的函数,那个东西可以对选定的单元格区域进行筛选,你可以正向选择,正向的时候可以多选,可以把需要选择的内容组成一个数组,实现多选。你也可以进行反选,但反选的时候你却不能把反选的条件建立成一个数组进行同样的操作。这些都只是针对一次筛选而言的,如果同一片区域多次叠加筛选,第一次你筛选的是第1列,第二次筛选的是第2列,我感觉如果第三次和第四次你反选的是第2列估计也行,但关键是我需要选择的那个数据是一个作死的不规范有两行甚至三行的标题栏,但是autofilter这个函数默认输出的东西就含有标题栏。本来我的数据范围是不规范的,如果我一开始就把前面三个标题栏给去掉。那么在我进行autofilter的时候,就会从纯粹的数据开始,显然那就不是我想要的东西了。因为哪怕最终筛选的数据是空,也会默认带入那个标题栏。所以你就搞不懂为什么步骤都对,但结果就不对。

autofilter之后要进行一个特殊粘贴,那个东西是只对可见的数据复制。就普通人的思维而言,我复制了可见的数据,那么理论上我就可以算出它有多少行,如果是0我就直接不输出了,如果大于0,那么我就可以输出,但实际上特殊粘贴又不可以用一般的技术判定到底筛选的结果是不是0。虽然也能判断有没有,但需要绕一个圈去实现这种功能,所以VBA为什么有那么神奇的思路呢?筛选可以进行,但是你不能对反向的数据批量进行处理,你也不能把特殊筛选结果直接保存为某个东西。当你觉得你大概可以把可见的部分保存到一个新的区域,然后你就可以去头去尾之类,但实际上当你再去查看那个新区域的时候发现原来是保存了个寂寞而已,那种神经性质跟那个可见区域是一样的。我不知道以前的人到底是怎么忍耐VBA这些奇怪脾性的,因为在接触这个之前我就已经接触过pandas。pandas的数据分为两个,一个是标题,另外一个是数据。输出的时候你可以都输出,你也只可以只输出其中的一部分。在使用pandas的时候,我没有解决过一些我的实际问题,我都是按照书本上的例子进行操作的,所以到底在我使用的过程中会不会也遇到一些像VBA这么神经,明明觉得可以,但实际上又不可能直接实现的事情不知道。

周五的下午,折腾了一番以后,我的目标数据最终可以复制到粘贴板,但是在VBA那个脚本结束之前,我就也得把那粘贴出来,否则当那个结束以后,剪贴板的内容就没有了。为什么会这样呢?不是说当我把数据复制到了剪贴板,而我又把Excel关掉,软件会问我要不要清空剪贴板的数据吗?但显然现在Excel都没关闭,我只是关闭了那个脚本,但我剪贴板却什么也没有了。

周五在回家的路上,我又努力地想了想这个问题。最后决定,我没有必要这么折腾自己获取剪贴板数据。反正全体数据不多,我直接对那个整体数据进行加工处理就行。加工处理的方法是首先从我的目标数据那里通过VBA获取我要的部分,然后输出到指定的位置,接着通过ADO+SQL进行数据处理。准确的来说,就是一个分组聚合、添加汇总以及排序。当然其实最后这个ADO+SQL的操作我也可以换成数据透视表,但如果那样的话,最后的排序我要让那完美的按照我想要的方式,我就只能先在Excel添加一个自定义的序列。无论是SQL还是数据透视表,分类汇总和排序都一定会比在VBA里用数组方便非常多。

思考一个问题的时候,有时可能我们有点过于钻牛角尖了,退一步,可能会有一个更清晰的思路。

进一步优化和debug

作者 xrspook
2024年8月22日 08:17

当年今日

又花了整整一天的时间去改进之前的两个转换程序,一个是用PQ写的,另外一个是用VBA写的。之前以现有的数据进行测试,没有发现问题,但实际上今天再去纠结,还是有个问题,就是当业务类别为轮换,出库的时候损耗的计算方式。损耗应该放在商品粮的账本,这个没有问题,之前也是这么处理的,但是商品粮的账本还有一个。储备粮油转入,这个东西就应该包含损耗和销售两方面的数据。之前只包含了销售的数据,忽略了损耗的那一部分。同样,在储备粮的账本,在转作商品粮油的数据那里也应该包含商品粮账本里面的损耗数据。这个东西平时做的时候一定会记得,因为单仓数据如果处理不到位无法清零,但是当要考虑的事情有很多的时候,就忘记了。在做这个程序的时候,我就已经考虑到这种损耗是一个很特殊的情况,但是我却没有进一步的考虑到这个东西特殊到要一变成三,通常情况下,一变二就可以了。

除了这个问题,以我现有的数据,基本上那两个程序都能运行出我想要的效果,但实际上,今年到现在为止,单位产生的那些数据还有一些业务类型没有包含进去,那些业务类型有些我可能会用到的,有些我是几乎用不到,但我用不到,不代表其他人也一定不会用到,所以从大的层面考虑,我还要把那些东西都考虑进去。

之前无论是在PQ还是VBA,某些字段的生成实际上是条件筛选,有可能是一个条件,也有可能是多个条件,那些条件里面会有很多个情况。在PQ里做条件筛选,还有个填写界面,但是在VBA里就纯粹靠iif的不断套叠。首先你得知道怎么套叠,然后当你套到一定程度的时候,自己也会被套进去,比如数着数着括号就对不上了,什么逗号双引号之类的偶尔也会制造幺蛾子。使用这种套叠可以实现我想要的效果,但是真的非常虐,而且一旦要进行数据维护,那简直就是个深渊,所以首先我想到的是要不要做另外一个索引的表,通过左外连接的方式指定某些字段必须匹配,然后就能获得我想要的新增字段。从可维护性来说,这样非常好,从代码的实现来说,这也很方便,但是后来我还是决定不在VBA里面实现这种左外的索引和直接在原始的表格里面就索引数据得出一个大表,然后再用大表进行后续的整理,因为要处理的大表其实数据不多,一年肯定不超2000条。之所以要这么干,首先是因为我考虑到可能使用这套方案的人会更容易接受这种直观生成的大表,他们可以直接核对数据,如果觉得不对,可以进行手动更改,但如果我把那个东西做在了VBA层面,程序运行不出来,或者运行出来的效果不是大家想要的,那么需要结果的那个人肯定不知道该怎么办。这种直接通过Excel的索引,先得出一个大表的方式,同样也会让PQ的程序不那么复杂,不需要搞那么多条件筛选。虽然PQ的条件筛选有界面,可以下拉选择,但需要选择的东西多了,很容易就会选错。

最后,事实证明我的这个做法是合理的,我把需要考虑的因素全部都考虑进去用全面的测试数据都模拟过以后,发现两个程序都能满足我的要求。当然了,在最终成功之前,我经历了不知道多少debug。你永远都不知道你会被什么卡住,又或者在什么地方被卡住,但被卡的次数多了,你就会觉得这很正常,继续死磕就行。

❌
❌