Mysql 在VBA中列出服务器的数据库和表

Mysql 在VBA中列出服务器的数据库和表,mysql,excel,vba,adodb,Mysql,Excel,Vba,Adodb,我试图列出服务器的数据库和表 我尝试在中使用like,但执行以下操作时返回null: Set Recordset1 = Connection.OpenSchema(Schema:=ADODB.SchemaEnum.adSchemaSchemata) MsgBox Prompt:=VBA.IsNull(Expression:=Recordset1.Fields.Item(Index:=0)) 下面我有一些适用于MySQL服务器的代码,但我想知道一种更标准且不特定于某个DBMS的方法 ' Refe

我试图列出服务器的数据库和表

我尝试在中使用like,但执行以下操作时返回null:

Set Recordset1 = Connection.OpenSchema(Schema:=ADODB.SchemaEnum.adSchemaSchemata)
MsgBox Prompt:=VBA.IsNull(Expression:=Recordset1.Fields.Item(Index:=0))
下面我有一些适用于MySQL服务器的代码,但我想知道一种更标准且不特定于某个DBMS的方法

' Reference:
' Microsoft ActiveX Data Objects 6.1 Library

Private Sub Macro()

  Dim Connection As ADODB.Connection
  Dim Recordset1 As ADODB.Recordset
  Dim Recordset2 As ADODB.Recordset

  Set Connection = New ADODB.Connection
  Connection.ConnectionString = "Driver={MySQL ODBC 5.1 Driver};Server=127.0.0.1;Port=3306"
  Connection.ConnectionTimeout = 0
  Connection.Open UserId:="root", Password:=""
  Set Recordset1 = New ADODB.Recordset
  Recordset1.ActiveConnection = Connection
  Recordset1.CursorLocation = ADODB.CursorLocationEnum.adUseClient
  Recordset1.Source = "SHOW DATABASES"
  Recordset1.Open
  Set Recordset2 = New ADODB.Recordset
  Recordset2.ActiveConnection = Connection
  Recordset2.CursorLocation = ADODB.CursorLocationEnum.adUseClient
  Do While Not Recordset1.EOF
    Connection.Execute "USE " & Recordset1.Fields.Item(Index:="Database").Value
    Recordset2.Source = "SHOW TABLES"
    Recordset2.Open
    Do While Not Recordset2.EOF
      Debug.Print Recordset1.Fields.Item(Index:=0).Value & " - " & Recordset2.Fields.Item(Index:=0).Value
      Recordset2.MoveNext
    Loop
    Recordset2.Close
    Recordset1.MoveNext
  Loop
  Set Recordset2 = Nothing
  Recordset1.Close
  Set Recordset1 = Nothing
  Connection.Close
  Set Connection = Nothing

End Sub

每个RDBMS都有自己的SQL风格。SQL Server支持表值函数和常用的表表达式CTE,MySQL不支持,但有一个整洁的group_concat函数;Oracle有不同的语法,Access有其自身的局限性和特殊性,DB2也是如此——如果您能够编写一个适用于所有RDBMS的SQL查询,那您就非常幸运了

使用过程方法,您需要一种方法让代码知道要使用什么样的SQL。您可以使用枚举:

公共枚举关系数据库 不支持 SqlServer MySql 神谕 结束枚举 然后,您可以使用切换逻辑来获得正确的SQL语法,以满足您的需要:

私有函数GetTableInfoQueryByVal db作为RDBMS作为字符串 选择案例数据库 案例SqlServer GetTableInfoQuery=从sys.Tables中选择*; 案例MySql GetTableInfoQuery=MySQL特定查询; 案例预言家 GetTableInfoQuery=Oracle特定查询; 其他情况 错误:Raise 5,TypeNameMe,不支持指定的RDBMS 结束选择 端函数 这会起作用,但很快就会变得烦人冗长,现在您有多个函数,包含不同风格的SQL语法,以及更多针对不同连接字符串的语法,维护这些函数最终会成为一场噩梦——更不用说调试了

问题不在于支持多个RDBMS,问题在于过程方法。面向对象编程带来了更干净的东西。在任何典型的C或Java数据访问代码中,RDBMS都是使用接口从消费代码中抽象出来的——该模式被称为Repository,它的主要优点是消费代码根本不关心它使用的是什么RDBMS

定义一个公开所需功能的接口:

“@Interface iTableInformationLocatory 选项显式 作为对象的公共函数GetTableInfo 端函数 通常,一个更通用的存储库接口可能如下所示:

公共函数GetAll作为对象 端函数 公共函数GetByIdByVal id与对象一样长 端函数 公共子DeleteByVal id的长度 端接头 作为对象的公共子SaveByVal实体 端接头 在支持泛型的语言中,您不需要As对象,并且可以保持类型安全性-但是由于VBA不支持泛型,例如VB.NET中的某个列表,所以Object就足够了

因此,我们的想法是针对IRepository接口编写代码:

作为ITableInformationDepository的公共子DoSomethingByVal存储库 作为对象的Dim信息 Set infos=repository.GetTableInfo “……做事。。。 端接头 请注意DoSomething如何只知道ItableInformationLocatory抽象接口,而不关心它是否真正影响了SQL Server、MySQL或Oracle。在代码/宏的入口点附近或入口处,您将创建实际具体类型的实例:

公共亚宏观经济1 作为iTableInformationDepository的Dim存储库 Set repository=New SqlTableInfoRepository DoSomething存储库 '... 端接头 如果Macro1突然需要关闭MySqlTableInfoRepository,那么在新的MySqlTableInfoRepository类模块上实现ITableInfoRepository接口,并实例化该类:DoSomething不会引起注意

可以使用Implements关键字实现接口。例如,SqlTableInfoRepository实现可能如下所示:

选项显式 实现ITableInformationPository 私有函数ITableInformationLocatory_GetTableInfo作为对象 Const sql=从系统表中选择* Dim conn作为ADODB连接 '... 端函数 您可以让GetTableInfo返回ADODB.Recordset,但是不同实现之间的列名可能不同,您不希望这样。因此,要么确保所有实现选择相同的列,要么将查询结果抽象到一个实体对象后面,该实体对象形式化了表信息记录的外观,并返回这些实体的集合:

'TableInfoEntity类 选项显式 作为字符串的公共数据库名 公共表名为字符串“SQL Server:包括”dbo“架构 公共列名称作为字符串 作为字符串的公共数据类型 '... 类似地,如果您有一个SqlOrderHeaderRepository,那么您可能有一个OrderHeaderEntity类模块,以便所有处理订单头的IRepository实现都具有相同的订单头外观概念:

选项显式 公共订单日期为日期 公共客户ID,只要 公共销售人员尽可能长 作为字符串的公共描述 '... 通过这种方式,可以使用IRepository接口执行某些操作或任何代码 esn甚至不需要了解ADODB,并且可以使用OrderHeaderEntity、OrderDetailEntity、CustomerEntity、SalesRecruption以及构成域的任何其他类


是的,OOP需要更多的工作和更多的模块。但结果是,您现在看到的模块具有明确定义的职责,其中SQL Server语法在一个位置,MySQL语法在另一个位置,Oracle语法在另一个模块中,没有任何切换逻辑。要扩展它并支持新的RDBMS,您甚至不需要接触现有的代码-您只需实现所需的类,这样代码就可以与新的RDBMS一起工作,并在入口点将其连接起来:一旦完成,交换RDBMS所需要做的就是更改正在实例化的具体类,并在入口点将参数注入到使用代码中。

将其作为存储过程写入sql,然后从excel中执行。我假设这和sql server一样是可能的。然后,您可以编写一些漂亮的动态sql后端来处理dbs上的循环。同样,我是从我对SQL Server所做的工作中推断出来的。@QHarr我更多地是在VBA方面寻找一种解决方案,该解决方案可以用于例如对外部服务器具有只读权限的连接。Recordset.OpenSchema为您提供有关查询结果的元数据,例如列名、数据类型、字段长度、,假设显示表执行SQLServer从SysStable中选择SELECT的操作,那么您需要一个正常的记录集,而不是它的元数据。如果需要支持多个RDBMS,请考虑在某个异构存储库接口后面抽象数据访问代码,比如说,公开一些GETALTABLESISFION方法,并使用SqlSomethingRepository、OracleSomethingRepository和/或MySqlSomethingRepository类实现该接口,然后针对ISomethingRepository编码,并利用多态性使代码与任何RDBMS一起工作,而无需重写所有数据访问代码;要支持新的RDBMS,只需实现接口并使用新类。c、 请注意,Oracle的all_表、SQL Server的sys.tables和MySQL的SHOW表与从ADO的OpenSchema提取信息并不是一回事。后者为您提供了ADO如何使用当前功能查看其模式的视图。由于您是从VBA执行此操作的,所以应该使用ADO的POV,而不是前者的POV,后者可以说更完整,更符合实际功能,但这不是您感兴趣的。您对元数据感兴趣,因为ADO为了从VBA方面高效地工作而理解元数据。