2025-11
9

又想起了Python

By xrspook @ 8:44:06 归类于: 烂日记

大概两年前,我买了一本叫《超简单 用Python让Excel飞起来》的书。那本书是怎么买的呢?我搜索关于Python跟Excel的书,然后就看到了它。说白了就是教你用Python去处理Excel。前面的部分是一些批处理,后面的那些是利用Excel的数据作图。批处理的部分我看得挺认真,也实际操作过。感觉基本上都是可以实现的,我在VSCode里写Python,然后引用Excel文件,最后把结果输出到Excel。的确,这样干可以批处理一些基本的问题,但关键是我是个完美主义者,所以我对输出格式有一定的要求,实际上这本书教你的东西不怎么包括具体调整格式本身。通常来说做法大概是读取文件,然后通过pandas处理,最后输出。在这里我学得比较认真的部分是批处理文件,无论是把一个工作簿的每个工作表分别另存为单独的工作簿还是把某个文件夹里面的工作簿全部都合并到一个工作簿里。这些翻来覆去的操作其中一个跑不掉的是要进行一定的循环,循环的思路搞清楚了以后一切都好说。学的时候很认真,也都全部尝试过了,但一段时间之后不用还是会全部都忘光光,最后剩下的只是知道一定可以通过批处理实现这些功能。

在电脑里面安装Python,然后通过这种方式的确是可以处理Excel文件,后来我也进一步对那些输出的文件进行了格式控制,但总的来说,还是有些不如人意的地方。就数据处理本身来说,Python没有任何问题,但关键是跟VBA这个原生的东西相比,在处理格式方面还是显得有点有心无力,又或者无法控制。一个很明显的地方就在于跟VBA相比,Python读取文件跟输出文件都得一定时间,可能数据处理本身不需要多少性能,但关键是打开文件关闭文件这都需要时间。后来机缘巧合之下,我知道了在VBA里可以通过ADO的方式用SQL解决数据的问题。ADO的方式意味着我并不需要真的打开文件,这样就节省了很多时间。以至于后来我用VBA取代了Python的功能,因为Python之所以好用是因为把Excel的数据传进去了以后,它对数据进行了一个类似数据库的标准化改造,然后用标准的语言实现某些功能。相比之下我觉得SQL更简单易懂。所以自从迷上了ADO+SQL以后,我基本上就没再用Python处理Excel了。我一直也没有进行太多高端的操作。可以肯定的是,如果我要做的话,实现同样的功能,我可以通过这两种途径分别得出方案。

回到一开始那本书,前面部分说的是一些批处理,后面部分说的是用Python作图,其实那个时候我并不明白为什么要用Python作图,因为Excel本来就可以作图,而且就控制来说Excel是可视化的,Python全部都得写上去,所以后面作图的部分我看得很潦草,直接快速掠过,只是知道能干这种事而已。

直到这一次数据分析需要做箱形图。Excel可以做箱形图,但对箱形图的控制不如人意,我想到了Python,也想到了R语言。我知道这两个东西通过某些包就可以轻松做出我想得到或者想不到的图。

R语言被我放下了太远,以至于我已经基本不知道该如何操作了,所以我选择先用Python探索一下作图。

2025-04
12

使用内部数据就会卡?

By xrspook @ 8:35:34 归类于: 烂日记

昨天说到一个很简单的SQL语句引用的数据库就只有一个字段两行记录,居然需要24秒才能得出结果。这让我觉得非常不可思议。首先可以肯定的是数据量非常少,为什么会出现这种问题呢?那只能是连接方面是不是出了什么故障,也不能说,那是失效的,因为的确还能查询得到想要查询的东西。在我测试的那个宏里面。我引用了两个文件,一个是外部文件,一个是内部文件。外部文件是含有比较多的数据,而内部文件,也就是我一开始说的那个只有两条数据。我感觉如果我的SQL再厉害一些,我对VBA再熟悉一些的话,那个内部文件可能我就不需要引用了,我直接就在VBA里创建一个数据库,然后把两条数据给写进去,用完以后就删掉,但显然现在我还没有很大的把握,一定能完美地做这件事情。把我某个文件里面的数据转化为数据库的数据我又烂熟,所以我采取了现在使用的这种方式。

ADO+SQL的这种方式,因为我们是跨表引用,所以意味着数据肯定来源于多个文件。他们有可能是同一个工作簿的不同工作表,也有可能是在不同的工作簿里。对我来说,只要是在一个工作簿里,那么起码一开始设定指向的时候就得有一个数据源。最经典的方式引用的那个数据源在使用数据的时候,在from后面不需要进行进一步的引用,其它的就得麻烦一些。我的第一个反应是,是不是引用数据的那个语句出现了变动呢?比如说现在我用的是Excel12。在数据源引用方面,我又折腾了一番,发现好像还是那样,没什么进展。会拖慢查询的那个数据源,我甚至把它放到了主数据源里,结果发现还是很慢,于是这就排除了是数据源引用语句变动导致缓慢。

所以这到底是什么原因造成的呢?因为我有很多个跨表引用的查询。有些查询是内部数据外部数据都有,有些只有外部数据,经过测试后我发现好像只有引用了内部数据的查询才会变慢。

为了证明我这个想法,星期三的晚上我编造了一些数据做测试。主要原理就是研究是不是数据源的关系导致这种变慢。一开始我的设计就是一个排列组合的方式,因为我默认的数据引用是要跨表的,所以我把数据源根据内内、内外、外外和外内这4种方式测试,实际上内内和外外是一回事,也就不需要进行两个引用了,所以我又把那两个东西拿了出来,同样进行测试。结果让人有点吃惊,凡是有内部数据参与的查询都会变慢。我测试的数据就只有一个字段几条记录,内内和内外需要12秒,外外需要0.1秒,外内需要24秒。这就能解释为什么我的那些变慢的查询起码都要24秒才能出结果。因为我永远把内部数据放在后面。究其原因是因为我设计那些查询的时候,我后来才想到要在那个查询文件里面搭一个加脚手架,把一些基础的东西加上去,在这种情况下我加得最多的是日期表。

关于这个测试的来龙去脉以及最终的结果,我在ExcelHome里面做了一个详细的帖子,在这里就不再具体阐述了。

折腾了这么一番以后,我发现这个锅还真不是我整出来的。造锅的是微软,不知道更新出了什么状况导致了。

Excel用多了,不知不觉我也居然能挑出微软的毛病。

2025-04
11

查询突然变慢

By xrspook @ 8:14:07 归类于: 烂日记

周三的下午跟往常一样,我点一下自己写的ADO+SQL+VBA的跨表查询文件,结果发现之前一秒就能出结果的东西等了好久,鼠标在那里转圈,我都甚至怀疑是Excel不知道因为什么原因卡死了,但我又有理由相信这不是卡死,因为当VBA要运行很长时间的时候,就会出现那种假死的状态。以前我遇到过这种情况,当我要查询一整年的平均库存的时候,就会这样,如果只是查询一个月的,没有问题。之所以一整年会出状况,是因为需要处理的数据的确有点多,如果我用的不是Excel的VBA的SQL,如果我要做的那个平均库存是在数据库里,用正儿八经规范标准的SQL做,我感觉不需要那么长时间。要长时间运行,无可避免会出现假死状态。周三下午,我就经历了一次,但我觉得那个查询不应该会假死。那个查询文件我用了接近两年,一直以来都没什么问题,因为数据不多,很简单,所以正常情况下,一秒之内出结果。其它查询可能需要的时间长一点,因为涉及的数据量比较大,但是这一次让我卡死的那个,一直以来,当我测试成功通过以后,就没有卡死过。

为什么会这样呢?我把自己写的所有查询文件全部都点了一遍。我觉得既然最简单的那个都要卡24秒,那些之前需要更长运行时间,会让人疯掉。测试结果让我有点意外。我猜想会更疯狂的那些居然没事,跟以前一样,运行时间没什么区别,但有些我感觉没有难度的东西,反倒卡住了。最卡的那个卡了97秒,实际上那个查询平时只需要0.5秒。

遇到这种情况,首先我不觉得是因为我的查询文件出了状况,因为这几天它没改动过,除非有人动了我的电脑,但这个几率太低。我觉得出状况最大的可能性是那个源文件的结构发生了某些变化,因为我引用的是Excel文件。用的那个范围是一个超级表,而如果在那个超级表以外的某个地方出现了一些奇怪的数据,比如说在纯日期的列里面出现了文本,那么就会导致在SQL转化数据的过程之中出现一些意想不到的事情。为了避免这种事情,我把源数据的那些空白行和列全部都删除处理。这就保证了我的原始数据是符合规定的,和以前的格式是一致的。接下来我觉得这会不会是更新的问题,所以我对windows系统以及Microsoft 365都进行了手动的更新。这两个东西的确都是需要安装更新的。更新完成了以后,问题依旧。

接下来我有两个选择,一个是就这样等死,反正现在的情况也不是出不了查询结果,只是用时很长而已。万一这真的是微软升级的bug,说不定哪一天他们就会解决掉,但也说不准他们永远都不解决这个我认为是bug的问题。第二个选择是我主动出击,逐个测试VBA查询里的语句。找出那条让我运行时间很长的语句,然后判定到底是什么原因。

那个理论上一秒就应该结束的查询,实际上是Excel工作表里面汇集了多个汇总查询。我只是把结果都在一个页面展示而已,所以首先,我要找出导致最终结果很慢的是哪个查询。这是一个反推的过程。让我有点意外的是,那些涉及很多数据的查询居然都没有问题,一个我觉得根本不会出问题的问东西里居然出问题了。出问题的那个查询实际上只涉及了一个字段两条数据。这简直让我震惊了,怎么居然这样呢?

这个问题是我之前没有遇到过的,但从发现这个奇葩之后,我觉得自己有点跟那杠上了。

2024-09
24

手贱惹的祸

By xrspook @ 8:45:12 归类于: 烂日记

VBA可以对普通的Excel文件用SQL查询,虽然我已经用的是超级表,理论上单元格的数据格式是一致的,但实际上这不是一个标准化的数据库,我没有办法在一开始的时候就对每个数据进行声明,所以在数据处理过程中就会出现这样那样说不准为什么的事情。

星期一的下午我跟往常一样做了些普通操作,最后当我用VBA生成一个汇总数据的时候发现弹出一个“标准表达式中数据类型不匹配”的警告。看到这个东西,我的第一反应是肯定是获取的数据里面有一些不规范的东西,比如说某一列通常是数字的,但是却出现了文字,但实际上我翻查了全部源数据都没有发现这个玩意。没办法之下,我只能做一个脚手架,一个一个的去排除,最后发现问题出在where里。where里有一个“性质<>某某某”的限定条件,问题就出现在那个地方,只要把这一句删掉,VBA是可以正常运行的,至于结果对不对不知道,反正能运行,然后我又回到了这一条的上一条结果,发现where里面的那个条件是没有问题的,所以这到底是什么问题呢?

然后我又想起,在进行普通操作的时候,我好像在某列数值的单元格里发现了一个汉字,说不准为什么那里会有一个汉字,但一个汉字足以影响那个单元格的类型。为什么我深有这种体会,因为如果某一列全部都是数字那么 VBA+ADO+SQL通常都会默认那是一个数值,但只要那一列里面有一个文字,所有东西都会被识别为文本。对数字进行聚合是理所当然没有问题的,但如果对文本进行这种操作,我不敢想象会出现什么东西。当然了,把文本作为分组条件,一点问题都不会有。

我感觉自己的VBA程序是健壮的,因为我已经用了他一年多了,之前从来没有出现过这种问题。有段时间经常会出现这样那样说不准什么问题的问题,但是过了一段时间之后,那些问题又自动消失了,所以我更相信那是有段时间windows更新导致某些框架不稳定导致了那段时间的意外。除非我对源数据做了更改,又或者是出现了某些意外,否则不会报这样的错误。

接着我又记起周一下午某个基本操作的时候,我好像发现在那个超级表的下面有一个“她”字。那个东西在不连续的单元格里,不是超级表的一部分,但关键是如果我用SQL获取数据,那肯定也会被纳入其中。看到那个莫名其妙的“她”字以后我已经把那删掉了,所以我看到的那个原始数据表格没有问题,但只是看上去没有问题。

折腾了好长时间未果,之后,我不得不重新翻出前一天晚上的源数据。然后手动把周一更新过的东西全部都贴回去。再去用VBA汇总,一切正常。在贴回去之前我首先用VBA测试了一下汇总没有问题,然后我才开始贴,贴了之后也没有问题。如果这个东西没有问题,也就是周一之前这个表格是没有问题的,但不知道周一进行了什么操作,导致了问题的出现。倒退以后重新贴数据没有问题,的确这个汇总也算保住了,但是我却一直放心不下,找不出问题的原因下一次依然会手忙脚乱。

吃过晚饭后我重新翻出有有问题的那个源数据。我的猜测是,因为数值列里面出现了一个文本,虽然我已经把文本删掉了,但是那个文本已经影响了那列单元格的类型,最终导致VBA弹出错误提示,虽然那个错误提示并不是出现在VBA调试发现的那一列。我的做法是在不修改VBA的前提下,把有问题源数据超级表下面的所有行全部删除,然后保存,再次运行vba,源数据通过了,可以正常运行。通过这样的操作,就能排除错误,非常有可能意味着我上面的猜测是对的。然后,我故意在数据列超级表外的单元格写一个字,然后保存,VBA汇总挂了。我把那个字删除,保存,VBA依然挂。但是当我把写过字的那一行删除,VBA汇总好了。这再一次验证了我的猜想。

这种事情该如何避免呢?首先不要手误,不要乱填。手误乱填这种事过去那么多年都从来没有发生过,为什么就发生了呢?到底是我的问题,还是另外一个人的问题?如果要避免这个事情,最好我在SQL引用源数据的时候就直接就限定为超级表范围,而不要把超级表所在的所有列都含进去。无论是哪一点,都是可以实现的。限定超级表的范围不太难,但关键是人手贱的这个行为,这一次出现在某个不知道为什么的单元格,下一次如果覆盖掉超级表的一个老数据呢?要避免这种人的失误非常难,但是人为什么会犯这种弱智到极点的失误呢?而且是犯了还毫不知情。

但总算这一次,我找出了可能的原因。

2024-09
14

升级VBA抓取方案

By xrspook @ 19:26:21 归类于: 烂日记

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

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

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

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

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

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