查询用户所有信息后只需要两个字段的信息_Excel VBA+ADO+SQL入门教程023:OpenSchema获取表信息...

点上方关注我们,每日1练,每天进步一点点346b5bca6cc4c96e8ddca21ab33e97fb.gif

 1.

我们在使用SQL语言对数据库数据进行查询之前,有时需要获取每张表的表名,甚至获取每张表每个字段的名称等;比如,当我们进行跨工作簿数据查询及汇总时,在不打开相关工作簿的情况下,如何快速遍历指定工作簿每个工作表的名称?

——Connection对象的OpenSchema方法可以帮助我们解决此类问题;它可以从提供者获取数据库模式的信息,并返回一个只读属性、静态游标的Recordset记录集。

语法如下:

Connection.OpenSchema (QueryType, Criteria,SchemaID)

第1个参数QueryType用来指定模式查询的类型,对我们而言,常用的有两个,adSchemaTables返回给定用户可访问的表,以及adSchemaColumns返回给定用户可访问的表的列;更多类型参数大家可以自行参考ADO帮助文件。

需要重点说明的是,QueryTe指定模yp式查询的类型常量,比如adSchemaTables,只有在ADO前期绑定的情况下才能够使用;如果ADO后期绑定,则需要使用相关的数值常量,adSchemaTables的对应值是20;adSchemaColumns的对应值是4。

第2个参数Criteria是可选的,用于限定模式查询结果的值的数组,也就是每个QueryType选项的查询限制条件数值。

第3个参数SchemaID也是可选的,为OLE DB规范未定义的提供者模式查询的GUID;如果QueryType被设置为adSchemaProviderSpecific则需要该参数,否则将不使用该参数。

第2~3参数我们基本用不到,所以照例就当没看见。

18dd5e8f533069ffd3250682b32de575.png

 2.

举个例子。

以下代码可以在不打开相关工作簿的情况下,获得该工作簿所包含的表名及相关信息。

Sub DoOpenSchema()    Dim cnn As Object, rst As Object, i As Long    Set cnn = CreateObject("ADODB.Connection")    cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Extended Properties=Excel 12.0;Data source=" & ThisWorkbook.Path & "\数据.xlsx"    Set rst = cnn.OpenSchema(20)    Cells.ClearContents    For i = 0 To rst.Fields.Count - 1        Cells(1, i + 1) = rst.Fields(i).Name    Next    Range("a2").CopyFromRecordset rst    cnn.Close    Set cnn = NothingEnd Sub

代码运行结果如下:

14618eddd0407649cf97384157207b92.png

代码说明:

Set Rst = Cnn.OpenSchema(20)

指定了我们所查询的类型,参数20对应的是adSchemaTables,也就是表。这里只能使用20作为参数,而不能使用adSchemaTables,至于原因,第一节讲过了。

结果表的第1行是Rst记录集中的字段名称,其中TABLE_NAME为表的名称,TABLE_TYPE为表的类型,DATE_CREATED为表创建的时间,DATE_MODIFIED为表结构最后修改的时间,注意是表结构最后修改的时间,不是相关表数据最后修改的时间。

另外,该段代码返回的是表的信息,而并非是工作表的信息。是的,这里的表和工作表当然并不是一个概念;表包含了定义名称、工作表等。比如标注黄色的部分,看见星光和看见月光,都是定义名称,而并非Excel工作表。

3eeacaa31aa9468c993f1b4d1b2170b5.png

通常而言,在Excel程序中,只有表名后缀为美金符号$的才是Excel工作表。

因此,如果我们只需要获取Excel工作表的名称,并舍掉其它信息,可以将代码修改如下:

Sub DoOpenSchema2()    Dim cnn As Object, rst As Object    Dim i As Long, s As String    Set cnn = CreateObject("ADODB.Connection")    cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Extended Properties=Excel 12.0;Data source=" & ThisWorkbook.Path & "\数据.xlsx"    Set rst = cnn.OpenSchema(20)    Cells.ClearContents    Do Until rst.EOF        If rst.Fields("TABLE_TYPE").Value = "TABLE" Then            s = rst.Fields("TABLE_NAME").Value            If Right(s, 1) = "$" Then                i = i + 1                Cells(i, 1) = s            End If            rst.MoveNext        End If    Loop    cnn.Close    Set cnn = NothingEnd Sub

结果如下:

b9ac3929931a3860f59a686c99223484.png

代码使用了Do Until语句循环遍历记录集,当记录集的EOF属性不为真时,先判断当前记录的TABLE_TYPE的类型是否为TABLE,如果条件成立,再判断表名的最末字符是否为$,如果条件再次成立,则将表名写入Excel,并将记录向前(MoveNext)移动一条。

……关于记录集的EOF属性我们以后讲Recordset对象时再详聊,这儿就混个面熟先。

混个面熟是很重要的事,可能关乎一生的幸福……不信……你听……

 3.

再举个例子,在不打开相关工作簿的情况下,获取指定工作簿每个表的字段信息

代码如下:

Sub DoOpenSchema3()    Dim cnn As Object, rst As Object, i As Long    Set cnn = CreateObject("ADODB.Connection")    cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Extended Properties=Excel 12.0;Data source=" & ThisWorkbook.Path & "\数据.xlsx"    Set rst = cnn.OpenSchema(4)    Cells.ClearContents    For i = 0 To rst.Fields.Count - 1        Cells(1, i + 1) = rst.Fields(i).Name    Next    Range("a2").CopyFromRecordset rst    cnn.Close    Set cnn = NothingEnd Sub

该段代码和第2节的第1段代码十分相似,只是将OpenSchema的参数从20改为了4,4对应的是adSchemaColumns,也就是列(字段)的信息。

结果如下:

4b192461b5fc0b570a5bdfe0d6d94e04.png

COLUMN_NAME是字段名,TABLE_NAME是字段所属表的名称。所谓表,同样并非一定是工作表,例如看见星光和他的好兄弟看见月光。

 4.

打个响指,来,咱们玩个稍微复杂点的提提神!

如果我们将第2和第3节的内容综合起来,可以解决一个很常见的表格问题:多工作表数据汇总。

多工作表数据汇总时,如果每张工作表的标题数量和排序都不一致,单纯的遍历表格+复制粘贴分表数据到总表的代码也就无济于事了,例如以下两个表,标题行的数量和排列顺序都不一样。

0e2fdeda7e973f8adbcc097992b810dc.png

使用VBA+ADO+SQL的解决方案如下:

代码比较长……瞅几眼,懂不懂的就随缘吧,反正日子长长又缓缓,不急一时,总有明白的那一天。

示例文件下载:

https://pan.baidu.com/s/1Fj4ghPGA-DSP5uzAx9TdVQ

提取码: q2e5

致安

再见

Sub ADOSheetTal()    Dim cnn As Object, rst As Object    Dim d1 As Object, d2 As Object    Dim strShtName As String, lngListNum As String, p As String    Dim i As Long, x As Long, aList, aKeys    Dim strSQL As String, strTitleNames As String    Set cnn = CreateObject("ADODB.Connection")    Set d1 = CreateObject("Scripting.Dictionary")    Set d2 = CreateObject("Scripting.Dictionary")    p = ThisWorkbook.Path & "\数据.xlsx" '汇总工作簿的路径+名称    cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Extended Properties=Excel 12.0;Data source=" & p    Set rst = cnn.OpenSchema(4) '读列的信息    Do Until rst.EOF        strShtName = rst.Fields("TABLE_NAME").Value '表名        If Right(strShtName, 1) = "$" Then '判断是否工作表            If Not d1.exists(strShtName) Then Set d1(strShtName) = CreateObject("Scripting.Dictionary")            '嵌套字典,strShtName为d1字典key,同时为新字典的名称            lngListNum = rst.Fields("COLUMN_NAME").Value '字段名称            d1(strShtName)(lngListNum) = "" '字段名装入对应工作表的字典            If Not d2.exists(lngListNum) Then d2(lngListNum) = ""            'd2字典记录不重复的所有表的字段名        End If        rst.MoveNext    Loop    aKeys = d1.keys '所有的表名    aList = d2.keys '所有表的字段名    For i = 0 To UBound(aKeys) '遍历表名        strShtName = aKeys(i): strTitleNames = ""        For x = 0 To UBound(aList) '遍历字段名            If d1(strShtName).exists(aList(x)) Then            '如果表中存在字段名字,则直接合并,中括号是避免字段名中存在特殊字符                strTitleNames = strTitleNames & ",[" & aList(x) & "]"            Else            '否则以NULL代替字段记录                strTitleNames = strTitleNames & ", null as " & aList(x)            End If        Next        strTitleNames = strTitleNames & ",'" & Left(strShtName, Len(strShtName) - 1) & "' as 来源表名 "        '将表名作为字段名装入字段        strSQL = strSQL & "select " & Mid(strTitleNames, 2) & " from [" & strShtName & "] Union all "        'Union语句多表合并    Next    Cells.ClearContents '删除汇总表数据    [a1].Resize(1, UBound(aList) + 1) = aList '标题行    [a1].Offset(0, UBound(aList) + 1) = "来源表名"    Range("a2").CopyFromRecordset cnn.Execute(Left(strSQL, Len(strSQL) - 10))    Set d1 = Nothing: Set d2 = Nothing    cnn.Close    Set cnn = NothingEnd Sub

更多教程&练习

  • 001:零基础学Excel(一)什么是Excel?

  • 002:30个工作日后(含特定节假日)是哪天?

  • 003:连续区间查询的常用方法有哪些?


©看见星光 6679fe25f9e47a843293b935296dbc58.png
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值