sql查询当前⽉份_Vba实现查询在A表不在B表的内容
本⽂的⽬的是想讨论⼀下在vba⽤不同的⽅法实现查询在A表⽽不在B表的内容,以及⽐较各个⽅法的效率。主要涉及的⽅法是字典+数
组,SQL语句中的notexists及left join.
运⾏环境:EXCEL版本Microsoft EXCEL 2016,win10 32位
⽂章涉及内容如下:
⼀、需求
⼆、实现思路
三、SQL语句
< exists
2.left join
< in
四、数组与字典
五、⽐较与总结
⼀、需求
这⼀次的内容来源于⼀个VBA⾥⾯的⼀个提问,需求是在⼀份记录总表⾥⾯查询某个⽉的新增⽤户的⼿机号码。记录明细有两列,⼀列是时间,⼀列是⼿机号,原来数据是在数据库上的,为了提供测试数据源才转到EXCLE的。当时因为上班时间,也没细看,最近⽆聊的时候回想起这个,觉得有意思,⼜出来学习下。
数据源只有2列,共14037⾏。
⼆、实现思路
实现这个需求的思路挺简单的,
1、 获取某⽉份所有出现的号码
2、 获取⾮该⽉份出现的号码
3、 判断在1结果⼜不在2结果中即想要得到的结果了。
这⾥以6⽉份为例⼦,⽤下⾯两种⽅法实现。
三、SQL语句
既然提问是⽤sql语句,我们这⾥也先讨论这个。(本⽂不涉及sql语句基础,只是稍微提及涉及的知识点)
实现步骤1,2的语句分别如下。
strSQL1 = "select distinct ⼿机号 from [记录明细$] where 结束时间 >= #" & t1 &"# and 结束时间< #" & t2 &"#"
strSQL2 = "select distinct ⼿机号 from [记录明细$] where 结束时间 < #" & t1 &"# or 结束时间>= #" & t2 & "#
t1 ,t2,代表开始⽇期和结束⽇期,⽅便查询不同⽉份的记录。Distinct 返回不重复记录。
⾄于怎么⽐较出步骤3的结果,这⾥有两个不⼀样的语句供⼤家选择
1. not exists
样版:select A.ID from A where not exists (select ID from B whereA.ID=B.ID)
strSQL ="select ⼿机号 from (" & strSQL1 & ") asa where not exists (select ⼿机号 from (" & strSQL2 & ") as b where a.⼿机号=b.⼿机号)" ‘利⽤⼦查询,直接求得A表及B表明细再取需求的结果
strSQL ="select ⼿机号 from [Sheet2$] as a where not exists(select ⼿机号 from [Sheet1$] as b where a.⼿机号=b.⼿机
号)" ‘先求得A和B表的结果保存到EXCEL再针对该结果取需求。
Not exists是⾥回复的最详细的⼀个结果,所以这⾥也先提这个。这⾥,我⼀个⽅法提供了两个实现的语句,上⾯那个是直接⽤⼦查询,
将步骤1,2的嵌套进去。下⾯那个是将步骤1,2分别实现查询结果,对结果进⾏not exists⽐较。这样操作的原因会在总结⾥⾯⽐较效
果。
2. left join
strSQL = "select * from (" & strSQL1 & ")as a left join (" & strSQL2& ") as b on a.⼿机号=b.⼿机号 where b.⼿机号 is
sql语句查询不包含null" ’⽤⼦查询
strSQL = "select * from [Sheet2$] as a left join [Sheet1$]as b on a.⼿机号=b.⼿机号 where B.⼿机号 is null" ‘使⽤查询临时结
果,不⽤⼦查询
Left join .. on ..左外连接的语句(有时也写作left outer join .. on .. )以左表为基准,将两表的数据进⾏连接,然后将左表没有对应项显⽰为
NULL;换种说法就是,结果将显⽰左表中所有的项⽬,即使其中在右表中没有查到对应的值。
⼩插曲:⼀开始接触这个碰到本次的问题的时候,脑海⾥出现的就是以前数学的venn图,我还以为left outer join就是需求⾥A-B的差集(如
下图),就是结果了。后⾯查了才知道⾃⼰理解错了,left outerjoin 就是left join,是包含A的所有结果。
这⾥提供⼀下完整的代码:
t1 = #6/1/2020#: t2 = #7/1/2020# Set cnn = CreateObject("ADODB.Connection") Set rst = CreateObject("ADODB.Recordset") PathStr = "E:\2.xlsx" 'ThisW
3. not in
select A.ID from A where A.ID not in (select ID from B)
不管是⼝碑还是实际实践,not in 的效率真的是不也恭维。就是A表1000多,B表1000多的数据量,我也没办法等到结果出来,以⾄放弃
继续运⾏。所以这⾥只是提供⼀下语法,仅供参考娱乐(凑字数)。
四、数组与字典
上⾯SQL语句都已经实现了, 为什么还要在这⾥加上这个字典+数组的办法?也是凑字数的关系吗?有点,但⼤部分不是。数组与字典是
VBA最基础的东西,好像实现本需求也不是什么⿇烦的事情,所以我还是想试着实现⼀次⽐较⼀下效果,结果还真的出乎我当初的意料。
我的想法是建三个字典,⼀个存当⽉⼿机号所有记录,⼀个存⾮当⽉记录,另外⼀个存只在当⽉出现记录(即需求结果)。相当于思路的3步
骤都分别⽤⼀个字典来存储。代码如下:
t1 = #6/1/2020#:t2 = #7/1/2020#arr = Range("a2:c" & Range("a1000000").End(xlUp).Row).ValueSet d1 = CreateObject("scripting.dictionary"):Set d2 = CreateO
需要注意⼀下的是:虽然⽂件⾥⾯的⽇期格式没有问题,但是读取进数组体现出来的类别是string,所以我们还得⽤cdate函数来转换⼀
下。因为得到的结果不正确,调试的时候才留意到这点,原因也很简单,时间格式和字符串格式⽐较能有个正常的结果?所以调试过程要仔
细观察。
五、⽐较与总结
为了了解⼀下各个⽅法的运⾏效率,我记录了⼀下运⾏的时间,具体如下表。
⽅法运⾏时间(秒)
A表0.37
B表0.39
not exists19.46
left join0.20
not exists⼦查询449.79
left join⼦查询0.85
数组与字典0.49
发现没有?其实在EXCEL⾥⾯,结合数组和字典的⽅法要⽐sql语句效率更好⼀点点。
⽐较结论及⼀些⼩细节:
(以下结论只限于EXCEL⾥)
1、结合数组与字典的⽅法在查询汇总⽅⾯,效率要⽐SQL语句快⼀点。
2、同样是SQL语句,left join 要notexists要快得多。当然 not exists 要⽐notin也要快很多。同样是⽤not exists,嵌套⼦查询的效率直接求结果的效率显然要⽐不嵌套的慢很多。(当然,如果知道left join要快那么多,还费那事⽤not exists吗)
3、本⼯作簿的话不推荐SQL,⽐如本次的需求数据源,如果是放在代码当前的⼯作簿执⾏的话,效率会⽐放在另外⼀个⼯作簿的低⼀些。这就是为什么我在left join 的代码⾥⾯,路径不是thiswork的原因。
4、在vba ⾥⾯,⽇期和时间常量前后要加#号。
最后,虽然在本次的需求⾯前,数组+字典就能解决问题,效率还⽐SQL语句⾼,但是不代表建议⼤家不学习,不去了解SQL语句。相反的,我私下认为SQL语句的代码更简单,特别是在更复杂的查询汇
总⾥⾯,⽤SQL语句替代数组+字典节省很多代码量。当然啦,不管什么办法,熟练应⽤才是你的办法。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论