相关推荐recommended
在VBA中使用SQL
作者:mmseoamin日期:2024-04-27

VBA在处理大量的数据/计算时如果使用常规方法会比较慢,因此需要对其进行性能优化以提高运行速度,一般的方法是数组计算或者sql计算。SQL计算的速度最快,限制也是最多的,数组速度其次,灵活性也更高

如果要在vba中调用sql处理数据基本可以遵循一个套路,只要修改其中的SQL语句即可

调用sql处理数据VBA代码如下,其中’##### #####中的地方是每次运行时要根据情况修改的:

Sub Sql_Query()
 Dim Conn As Object, Rst As Object
 Dim strConn As String, strSQL As String
 Dim i As Integer, PathStr As String
 Set Conn = CreateObject("ADODB.Connection")
 Set Rst = CreateObject("ADODB.Recordset")
 PathStr = ThisWorkbook.FullName 
 Select Case Application.Version * 1 '设置连接字符串,根据版本创建连接(不同版本的excel连接是不同的)
 Case Is <= 11
    strConn = "Provider=Microsoft.Jet.Oledb.4.0;Extended Properties=excel 8.0;Data source=" & PathStr
 Case Is >= 12
    strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & PathStr & ";Extended Properties=""Excel 12.0;HDR=YES"";"""
 End Select
 strSQL = "Select * FROM [rawdata$]"   '####在这里改SQL查询语句####
 Conn.Open strConn '打开数据库链接
 Set Rst = Conn.Execute(strSQL) 	'执行查询,并将结果输出到记录集对象
 With ThisWorkbook.Sheets("sql data") 	'#####在这里更改输出的位置对应的表名####
      .Cells.Clear
      For i = 0 To Rst.Fields.Count - 1    '填写标题
        .Cells(1, i + 1) = Rst.Fields(i).Name	'在第一行输出字段名
      Next i
      .Range("A2").CopyFromRecordset Rst     '从A2单元格开始输出
      .Cells.EntireColumn.AutoFit '自动调整列宽
 End With
 Rst.Close  '关闭数据库连接
 Conn.Close
 Set Conn = Nothing
 Set Rst = Nothing
End Sub

接下来,开始学习SQL语句语法

1.基于一张工作表的查询语法

SQL语法格式比较固定,只需要根据特定的语法顺序,再根据需求加减关键字即可。首先我们给出一个比较全的格式如下:

 SELECT   [DISTINCT]   [TOP <数值>  [PERCENT]]   列标题  [聚合函数]   [[AS] <别名列标题>]   FROM  表或查询 [[AS] <别名>]   [WHERE <筛选条件>]  [ORDER BY <排序项>  [ASC|DESC]]                                

说明:

  1. <>表示必选项,[]表示可选项,|表示多选一。
  2. SQL语句中不区分大小写,上述式中的的大写意为SQL中关键字
  3. SELECT 关键字:选取关键字
  4. DISTINCT关键字:去除重复的行
  5. TOP 关键字:显示前几条记录
  6. PERCENT关键字:TOP 与 PERCENT 组合在SQL语句中的使用可以按照百分比提取数据
  7. AS关键字:给标题列重新命一个新名称
  8. FROM关键字:给定数据源的名称
  9. WHERE关键字:筛选条件语句
  10. ORDER BY关键字:排序,一般和ASC|DESC一起使用,将结果升序或者降序排列。

接下来详细讲解每一个关键字的使用:

SELECT关键字和FROM 关键字

SELECT关键字和FROM 关键字是每个SQL语句中都必须要有的关键字。SELECT关键字可以选取最终需要显示所有字段,而FROM关键字则用于告诉程序数据源的位置在哪里。VBA中一个最基本的SQL语句写法如下:

SELECT 列字段名1,列字段名2,列字段名3...... FROM [工作表名称$]

例如我们需要从student这一个sheet中取出ID,name,address,score这四列数据:

select ID,name,address,score from [student$]

也可以使用[]将列名括起来表示这是一个列名

select [ID],[name],[address],[score] from [student$]

如果需要取所有的列,可以直接使用“*”号来取全部的列,从而减少代码量

#*号是代表全部列
select * from [sheet1$]

AS关键字

AS关键字用于给字段或者数据源表取别名,从而简化一些比较长的表名或字段名

#从student表中选取姓名列,并重命名为Name
SELECT 姓名 AS Name FROM [Student$]

DISTINCT关键字

DISTINCT关键字功能是去重,语法结构为:

SELECT DISTINCT 要去重复值的字段1,要去重复值的字段2...... FROM [工作表名$]

举例如下:

#选取所有不重复的name
Select Distinct name From [student$]
#选取name和ID都不重复的数据
Select Distinct name,ID From [student$]

WHERE关键字

where关键字可以按条件筛选数据。WHERE语句后可以有一个或多个条件,条件之间可以用操作符AND 或者OR进行连接。

WHERE语句的语法结构如下:

SELECT 列字段名称 FROM [表名称$] WHERE 条件

where后的条件语句可以是运算符或逻辑判断,包含大于、小于、等于、不等于、大于或等于、小于或等于、IN、 BETWEEN、AND、NOT等。

#选取取消费金额等于100的数据
SELECT * FROM [test$] where 消费金额=100
#选取级别为A的数据
SELECT * FROM [test$] where 级别='A'
#选取级别不为A的数据
SELECT * FROM [test$] where 级别<>'A'
#选取级别为A,B,C,D的数据
SELECT * FROM [test$] where 级别 in ('A','B','C','D')
#选取取消费金额不为空的数据
SELECT * FROM [test$] where 消费金额 is not NULL
#选取取消费金额大于100且级别为A的数据
SELECT * FROM [test$] where 消费金额>100 AND 级别='A'

ORDER BY关键字

ORDER BY关键字可以对结果排序,升序的关键词为ASC,也是默认值,通常不指定。降序为DESC。语法结构如下:

SELECT 列字段名 FROM [工作表名称$] ORDER BY 指定列字段名 升序(降序)

按成绩进行升序排序的SQL语句如下:

Select * FROM [Sheet1$] ORDER BY 成绩 ASC

,如果要按两个或两个以上字段,那么字段与字段之间用号逗隔开,

Top关键字

TOP按顺序提取前n行的记录,语法结构如下:

SELECT TOP 3 * FROM [工作表名$]

如提取成绩前三名的记录

Select top 3 * FROM [Sheet1$A1:C17]  ORDER BY score

其中[Sheet1$A1:C17]这个表示工作表名Sheet1的工作表A1:C17的这个单元格区域,加上了指定的单元格区域为数据。可以根据自己的实际情况,来改变.

不在同一张表上显示结果,而且数据源规范,就可以直接用[工作表名$]。或者书写的时候写上列名不用星号(“*”)

这两个也是和标准sql之间差别较大的地方

TOP 与 PERCENT 组合在SQL语句中的使用可以按照百分比提取数据,例如按成绩降序排列提取前30%

Select TOP 30 PERCENT * FROM [Sheet1$A1:C17]  ORDER BY 成绩 DESC
聚合函数

SQL聚合函数包括sum,count,avg,max,min等,与excel的公式有同样的效果,但是在大数据量的情况下速度会提升很多,而且在多条件求和时会比使用sumifs简单,直观的多

多条件求和的语法结构为:

SELECT 分类字段1, 分类字段2 , SUM(统计字段) as 产品总数 From [Sheet1$] GROUP BY 分类字段1, 分类字段2

例如按照日期和姓名汇总产品数:

SELECT 日期, 姓名, SUM(产品数) as 产品总数 From [Sheet1$] GROUP BY 日期, 姓名

注意事项:

1.在SQL语句中SQL语句英文不区分大小写,但标点符号必须是英文半角状态下输入,字段名也必须跟原来的一样。

2.使用SQL语句的时候,必须避免列字段中使用下面的特殊字符:

空格、双引号(")、撇(')、数字标记(#)、百分号(%)、大于号(>)、小于号(<)、叹号(!)、句号(.)、方括号([或])、星号(*)、美元符号($)、分号(;)、脱字号(^)、圆括号((或))、加号(+)、反斜杠(\或/)。

如果在源数据表的列字段使用了这些特殊字符,那么在使用SQL语句列出各字段的数据时,就会发生错误。为了规范使用SQL语句,在对数据源字段命名时,尽量避免使用这些特殊字符。

日期数据在SQL表达式中的应用

在SQL表达式运算符条件中,要查询日期和时间类型的数据,需要在数据值两端加上井字符号(#)以表示日期类型。

日期可以有多种表示方式,最符合中国人的习惯是“年-月-日”或“年/月/日”的表示方式。也就是说年月日之间的分隔符可以用“-”或“/”。

例如表示2013年10月1日

可以采用以下表达式:

年月日
#2013-10-1#
年日月
#2013-1-10#
年月日
#2013/10/1#
日月年
#1/10/2013/#
月日年
#10/1/2013#
以表达式在系统无错识别最高的应该是
月/日/年
#10/1/2013#
如何查询二个日期间的数据

Where … AND…语句,例如查找大于等于2013年10月1日,小于等于2013年10月7日的数据,的SQL表达式为:

SELECT * From [Sheet1$A:C] where 日期>=#10/1/2013# And 日期<=#10/7/2013#

还可以以单元为动态引用查询两个日期内的数据,如下图所示

 strSQL = "SELECT * From [Sheet1$A:C] where 日期>=#" & Range("J1") & "# And 日期<=#" & Range("K1") & "#"

在VBA中使用SQL,在这里插入图片描述,第1张

like关键字

Like 操作符用于在 WHERE 子句中搜索列中的模糊匹配

Select 列字段名 From [工作表名$] Where 列字段 Like '关键字'

可以加上通配符% (相当于函数公式中的通配符*)

strSQL = "Select * from [Sheet1$] Where 姓名 like '[AB]%'"

这一语句表示匹配姓名以A开头或B开头的数据

同样的可以反向查询姓名不以A开头或B开头的数据

strSQL = "Select * from [Sheet1$] Where 姓名 like '[!AB]%'"
--or
strSQL = "Select * from [Sheet1$] Where not 姓名 like '[AB]%'"
in关键字

In运算符允许 在 WHERE 子句中规定多个值,语法如下:

Select 字段 From [表名$] Where 字段 In(条件1, 条件2,条件3, ....)

如果在In的条件中不是数值类型,一定要加上引号。

eg:

Select *  FROM [Sheet1$A:D] where 省份 in('广东','广西')

2.两表的上下拼接

将两表连接起来的语句一般是UNION和UNION ALL

UNION ALL是查询所有记录(直接连接,可以重复),UNION只查询不重复(指整条记录不重复,取唯一)的记录,两种语句如果有重复记录,则查询结果就不一样。

在数据库中,UNION和UNION ALL关键字都是将两个结果集合并为一个,但这两者从使用和效率上来说都有所不同。

UNION在运行时先取出几个表的结果,再用排序空间进行排序删除重复的记录,最后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。

而UNION ALL只是简单的将两个结果合并后就返回。这样,如果返回的两个结果集中有重复的数据,那么返回的结从效率上说,UNION ALL 要比UNION快很多,所以,如果可以确认合并的两个结果集中不包含重复的数据的话,那么就使用UNION ALL。

例如将sheet1与sheet2中的数据连接起来:

SELECT 日期,姓名,产品数 From [Sheet1$] UNION SELECT 日期,姓名,产品数 From [Sheet2$]

这个是在两张表的格式一样的情况下直接连接,但是有些情况下两表的格式并不一样,这个时候可以使用下列语句:

例如sheet1中有日期,姓名两个字段,而sheet2中有姓名,产品数两个字段,需要上下连接两个表格:

SELECT 日期,姓名,null as 产品数 From [Sheet1$] UNION SELECT null as 日期,姓名,产品数 From [Sheet2$]

即使用null加列拼成格式相同的两个表格再连接

3.两表的左右连接

两表的左右连接即是join关键字

SQL代替Vlookup 精确查找(左连接 “Left Outer JOIN” 用法),语法结构为:

Select 表名 .字段1,表名 .字段2,表名 .字段3,表名 .字段4 FROM 查询表 AS 别名1  Left Outer JOIN 被查询表 AS 别名2 ON  别名1.字段名=别名2.字段名

例如:

SELECT A.姓名,B.性别,B.部门 FROM [Sheet2$] AS A Left Outer JOIN [Sheet1$] AS B ON A.姓名=B.姓名
--简写为
SELECT A.姓名,性别,部门 FROM [Sheet2$]A Left JOIN [Sheet1$]B ON A.姓名=B.姓名

join除了left join外还有right join,inner join等,之间的区别与sql语句都是一致的。注意VBA中的SQL是不支持outer join连接的

4.三表连接

如果需要连接多个表,可以按照上述两表连接的语法写多次即可。注意语句中的括号,在VBA SQL中不使用括号会导致错误

select A.姓名,B.性别,C.部门 from ([Sheet2$] as A left JOIN [Sheet1$] as B on A.姓名=B.姓名) left JOIN [Sheet3$] as C on A.姓名=C.姓名

5.数据透视表

TRANSFORM语句可以实现像透视表一样的显示结果,语法结构为:

TRANSFORM 汇总方式  SELECT 行标签 from 表名 group by 行字段 PIVOT 列标签

这一语句是非常常用的方法,要注意TRANSFORM后的汇总方式为一个聚合函数(一般为sum),同时后续的SELECT语句中不要加入a字段/b字段或者having语句,否则会导致语句错误无法运行

eg:

原始数据表如下

在VBA中使用SQL,在这里插入图片描述,第2张

运行如下语句输出数据透视表:

TRANSFORM Sum(数量) Select 产品名称 from [Sheet1$] group by 产品名称 PIVOT 款号

可得到如下结果:

在VBA中使用SQL,在这里插入图片描述,第3张

TRANSFORM语句话还可以加入一些自定义的设置:

TRANSFORM 汇总方式  SELECT 行标签 from 表名 group by 行字段 PIVOT 列标签 in [列标签值1,列标签值2,列标签值3.....]

使用in可以限制列标签的内容,同时可以规定列字段值的展示顺序

4.一些其他SQL语句的补充

条件判断/case语句的替代

在SQL中使用广泛的case关键字在VBA SQL中的实现方式为IIF,IIF的语法为:

IIf(Logical EXPression, Numeric Expression1, Numeric Expression2)

如果 Logical Expression 取值为 TRUE,则此函数返回 Numeric Expression1,否则,返回 Numeric Expression2。

例如:

当site列填NA时,将if_address设为N,否则设为Y

select name,iif([site]='NA','N','Y') as if_address form [student$]

同理,Logical Expression可以使用isnull,数字等值判断语句等

同时iif语句对符合条件的数据进行计算。例如如果是赠送的,实际的花费为0,否则为原价购买计算花费

select 客户,sum(iif(buying_type='赠送',price,0)) as cost  from  [order$]
从其他文件中引用数据

如果SQL中的数据涉及到不同的Excel表,可以直接从其他文件获取数据的SQL语句:

Select * From [盘符:\路径\工作簿名1.后辍名].[工作表名$] Union All Select * From [盘符:\路径\工作簿名2.后辍名].[工作表名$] Union All Select * From [盘符:\路径\工作簿名3.后辍名].[工作表名$]
数据没有列标题

如果工作表没有列标题,用F1,F2,F3,F4…这样代替

字段名解决特殊字符问题

如果列标题中有特殊字符如单引号、斜杠、百分号等。或者关键字:from、in、select、where等,可以用[ ]将字段包起来表示这是一个字段名,例如:

Select [%百分比]  FROM [Sheet1$] 

在VBA中使用SQL,在这里插入图片描述,第4张