查询用户所有信息后只需要两个字段的信息_Excel VBA+ADO+SQL入门教程023:OpenSchema获取表信息...
点上方关注我们,每日1练,每天进步一点点
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参数我们基本用不到,所以照例就当没看见。
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
代码运行结果如下:
代码说明:
Set Rst = Cnn.OpenSchema(20)
指定了我们所查询的类型,参数20对应的是adSchemaTables,也就是表。这里只能使用20作为参数,而不能使用adSchemaTables,至于原因,第一节讲过了。
结果表的第1行是Rst记录集中的字段名称,其中TABLE_NAME为表的名称,TABLE_TYPE为表的类型,DATE_CREATED为表创建的时间,DATE_MODIFIED为表结构最后修改的时间,注意是表结构最后修改的时间,不是相关表数据最后修改的时间。
另外,该段代码返回的是表的信息,而并非是工作表的信息。是的,这里的表和工作表当然并不是一个概念;表包含了定义名称、工作表等。比如标注黄色的部分,看见星光和看见月光,都是定义名称,而并非Excel工作表。
通常而言,在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
结果如下:
代码使用了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,也就是列(字段)的信息。
结果如下:
COLUMN_NAME是字段名,TABLE_NAME是字段所属表的名称。所谓表,同样并非一定是工作表,例如看见星光和他的好兄弟看见月光。
4.
打个响指,来,咱们玩个稍微复杂点的提提神!
如果我们将第2和第3节的内容综合起来,可以解决一个很常见的表格问题:多工作表数据汇总。
多工作表数据汇总时,如果每张工作表的标题数量和排序都不一致,单纯的遍历表格+复制粘贴分表数据到总表的代码也就无济于事了,例如以下两个表,标题行的数量和排列顺序都不一样。
使用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:连续区间查询的常用方法有哪些?
©看见星光
查询用户所有信息后只需要两个字段的信息_Excel VBA+ADO+SQL入门教程023:OpenSchema获取表信息...相关推荐
- vba ado 执行多条mysql 语句,Excel VBA+ADO+SQL入门教程003:SQL查询中字段技巧的总结...
原标题:Excel VBA+ADO+SQL入门教程003:SQL查询中字段技巧的总结 本章概要: 1,几个概念 1.1, 数据库和Excel工作簿 1.2,数据表和Excel工作表 1.3,记录.字段 ...
- 《SQL 入门教程》第07篇 多表连接查询
<SQL 入门教程>专栏目录 第01篇 SQL 简介 第02篇 查询初体验 第03篇 查询条件 第04篇 结果排序 第05篇 限定结果数量 第06篇 分组与汇总 第07篇 多表连接查询 第 ...
- 【Spring Security】如何实现多设备同一时间只允许一个账号登录(即前登录用户被后登录用户挤下线)?只需简单两步!
1.需求分析 在同一个系统中,我们可能只允许一个用户在一个终端上登录,一般来说这可能是出于安全方面的考虑,但是也有一些情况是出于业务上的考虑,需求就是业务原因要求一个用户只能在一个设备上登录. 要实现 ...
- 2021-01-15:用户登录,保存30天的免登,只允许两个设备登录,如果有第三个设备登录,踢掉第一个。改密码的时候,所有设备需要下线。这个逻辑怎么实现呢?
福哥答案2021-01-15: 一.我想到的答案. 为什么不能用设备id? 接口调用,如果是网页,设备id是无法获取的.另外,设备id可以作假. 为什么不能用ip区分? 有些网络(某些校园网),对外就 ...
- 18.一个人赶着鸭子去每个村庄卖,每经过一个村子卖去所赶鸭子的一半又一只。这样他经过了七个村子后还剩两只鸭子,问他出发时共赶多少只鸭子?经过每个村子卖出多少只鸭子?
18.一个人赶着鸭子去每个村庄卖,每经过一个村子卖去所赶鸭子的一半又一只.这样他经过了七个村子后还剩两只鸭子,问他出发时共赶多少只鸭子?经过每个村子卖出多少只鸭子? #include <stdi ...
- 一个人赶着鸭子去每个村庄卖,每经过一个 村子卖去所赶鸭子的一半又//一只。 这样他经过了 七个村子后还剩 两只鸭子,问问他出发时共赶多少//只鸭子?经过每个村子卖出多少只鸭子?
.一个人赶着鸭子去每个村庄卖,每经过一个 村子卖去所赶鸭子的一半又 //一只. 这样他经过了 七个村子后还剩 两只鸭子,问问他出发时共赶多少 //只鸭子?经过每个村子卖出多少只鸭子?int i,j=2 ...
- mysql平均值函数保留两位小数点_用sql的avg(score)求完平均值后,保存两位小数的方法(用于查询或视图)...
window7系统怎么找到开始运行命令 右击开始->属性->开始菜单->自定义>点击运行命令(选择)->确定 Android DownloadProvider学习 Dow ...
- mysql不同服务器数据库查询_不同服务器不同数据库两张表连接查询使用经验
使用SQL语句连接查询位于两个不同的服务器不同的数据库中的两张表,最初将SQL语句写成以下形式select*fromProduct pinnerjoin opendatasource('SQLOLED ...
- 查询计算机上可用端口的两种方法
在设备远程控制中,经常需要搜索设备上已安装端口号,例如在"计算机"→"设备"能看到的端口(COM和LPT).本文介绍的两种方法都是通过访问注册表实现的. 方法一 ...
最新文章
- client中周期性边界_HFSS中周期性边界条件的设置
- 3种python调用其他脚本的方法,你还知道其他的方法吗?
- android中图型的阴影效果(shadow-effect-with-custom-shapes)
- layui登录页面写入数据_layui基本使用(动态获取数据,并把需要的数据传到新打开的窗口)...
- 懂得一些基本常识,就不会被《非酒精類致命飲料》或者叫做《我一辈子都不再喝可口可乐》的这篇文章所蒙蔽...
- 大整数乘法--leetcode Multiply Strings
- 运行报错Error starting ApplicationContext
- paip.接入支付接口功能流程总结
- 浅谈React Event实现原理
- 东华大学计算机学院推免名单,东华大学2020年接收推荐免试攻读硕士研究生预申请公告...
- python进阶高级技能:Python退火算法在高次方程的应用
- 基于stm32/单片机/DSP/Java的毕业设计 课程设计
- angularjs-大漠穷秋
- mysql为什么要用b+树
- 045 [转载]DNS RPC 分析
- python全栈是什么?
- backlight子系统二
- 以http进行git
- jdk_8u201_x64下载直链
- 申购新股流程|申购新股流程介绍
热门文章
- IDEA Tips:Debug跳转任意行
- 皮一皮:今年的网友不够优秀啊。。。
- 2021年6月程序员工资排行榜,南京这是怎么了?有啥大动作吗?
- Spring Boot 2.4.3、2.3.9 版本发布,你准备好了吗?
- 皮一皮:我好像知道了什么...
- 每日一皮:你不知道你的骑手为了给你送餐要经历什么...
- SQL 查询总是先执行SELECT语句吗?你们都错了!
- 世界很大,先从这几个公众号看起!
- java poi 导出 国际化_更好用的excel国际化多语言导出
- mobile former测试