Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ms-access/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用python从MS Access数据库检索所有保存的查询?_Python_Ms Access_Pyodbc - Fatal编程技术网

如何使用python从MS Access数据库检索所有保存的查询?

如何使用python从MS Access数据库检索所有保存的查询?,python,ms-access,pyodbc,Python,Ms Access,Pyodbc,基本上,我使用python比较了2个access数据库 我没有权限手动打开任何access文件,它必须完全在python中完成 我需要检索完整的 查询名称 关联查询代码 我不会提前知道查询的名称 我已经尝试了一些几乎奏效的解决方案,我在下面列出了3个解决方案 部分解决方案1 我几乎让它使用win32com和CurrentDb.QueryDefs方法来检索每个查询的代码 但是,连接的顺序似乎不是在两个数据库之间确定存储的。 (这似乎取决于MSysQueries中条目的顺序) i、 e.在一个

基本上,我使用python比较了2个access数据库

我没有权限手动打开任何access文件,它必须完全在python中完成

我需要检索完整的

  • 查询名称
  • 关联查询代码
我不会提前知道查询的名称

我已经尝试了一些几乎奏效的解决方案,我在下面列出了3个解决方案


部分解决方案1

我几乎让它使用
win32com
CurrentDb.QueryDefs
方法来检索每个查询的代码

但是,连接的顺序似乎不是在两个数据库之间确定存储的。 (这似乎取决于MSysQueries中条目的顺序)

i、 e.在一个数据库中,连接的文本可以是

on Table1.ColumnA = Table2.ColumnA & Table1.ColumnB = Table2.ColumnB
在另一个

on Table1.ColumnB = Table2.ColumnB & Table1.ColumnA = Table2.ColumnA
显然,这些将导致相同类型的联接,但不是完全相同的查询文本

如果我直接比较文本,它们不匹配。在比较之前处理文本似乎是一个坏主意,因为有很多角落案例

示例代码

objAccess = Dispatch("Access.Application")
objAccess.Visible = False

counter = 0
query_dicts = {}
for database_path in (new_database_path, old_database_path):

    # Open New DB and pull stored queries into dict
    objAccess.OpenCurrentDatabase(database_path)
    objDB = objAccess.CurrentDb()

    db_query_dict = {}
    for stored_query in objDB.QueryDefs:
        db_query_dict[stored_query.name] = stored_query.sql

    query_dicts[("New" if counter == 0 else 'Old')] = db_query_dict

    objAccess.CloseCurrentDatabase()
    counter += 1

部分解决方案2

第一个解决方案失败后,我尝试在msysquerys上编写查询并强制排序。但是,pyodbc没有对该表的读取权限

看起来您无法从python本身授予读取权限,这是一个问题,在这里可能是错误的

查询:

SELECT MSysObjects.Name
          , MSysQueries.Attribute
          , MSysQueries.Expression
          , MSysQueries.Flag
          , MSysQueries.Name1
          , MSysQueries.Name2
FROM MSysObjects INNER JOIN MSysQueries ON MSysObjects.Id = MSysQueries.ObjectId
order by MSysObjects.Name
          , MSysQueries.Attribute
          , MSysQueries.Expression
          , MSysQueries.Flag
          , MSysQueries.Name1
          , MSysQueries.Name2
部分解决方案3

我尝试的另一件事是让python将
VBA
模块存储到数据库中,该模块将元数据信息写入表中,然后通过
pyodbc
读取该表

我可以添加模块,但access数据库不断提示输入模块名称。我找不到关于如何使用方法调用命名模块的文档

示例代码:

import win32com.client as win32

import comtypes, comtypes.client
import win32api, time
from win32com.client import Dispatch

strDbName = r'C:\Users\Username\SampleDatabase.mdb'
objAccess = Dispatch("Access.Application")
# objAccess.Visible = False
objAccess.OpenCurrentDatabase(strDbName)
objDB = objAccess.CurrentDb()


xlmodule = objAccess.VBE.VbProjects(1).VBComponents.Add(1)  # vbext_ct_StdModule

xlmodule.CodeModule.AddFromString(Constants.ACCESS_QUERY_META_INFO_MACRO)

objAccess.Run("CreateQueryMetaInfoTable")

objAccess.CloseCurrentDatabase()


objAccess.Quit()
我试图添加的宏

Sub CreateQueryMetaInfoTable()
    Dim sql_string As String

    # Create empty table
    CurrentDb.Execute ("Create Table QueryMetaInfoTable (QueryName text, SqlCode text)")

    Dim qd As QueryDef

    For Each qd In CurrentDb.QueryDefs

        # insert values
        sql_string = "Insert into QueryMetaInfoTable (QueryName, SqlCode) values ('" & qd.Name & "', '" & qd.SQL & "')"

        CurrentDb.Execute sql_string

    Next


End Sub

在@Gord Thompson的帮助下,我现在有了一个有效的解决方案

我需要先连接OLEDB以授予读取权限,生成一个包含所需信息的非系统表,然后通过ODBC将该表读回

CONNECTION_STRING_OLEDB = "PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE={};Jet OLEDB:System Database={};" 

ACCESS_QUERY_META_INFO_CREATE = """SELECT MSysObjects.Name
          , MSysQueries.Attribute
          , MSysQueries.Expression
          , MSysQueries.Flag
          , MSysQueries.Name1
          , MSysQueries.Name2
INTO QueryMetaInfo       
FROM MSysObjects INNER JOIN MSysQueries ON MSysObjects.Id = MSysQueries.ObjectId
order by MSysObjects.Name
          , MSysQueries.Attribute
          , MSysQueries.Expression
          , MSysQueries.Flag
          , MSysQueries.Name1
          , MSysQueries.Name2"""


ACCESS_QUERY_META_INFO_READ = """select * from QueryMetaInfo
order by Name
      , Attribute
      , Expression
      , Flag
      , Name1
      , Name2;"""

ACCESS_QUERY_META_INFO_DROP = "DROP TABLE QueryMetaInfo"

connection = win32com.client.Dispatch(r'ADODB.Connection')
DSN = CONNECTION_STRING_OLEDB.format(database_path, r"C:\Users\C218\AppData\Roaming\Microsoft\Access\System.mdw")
connection.Open(DSN)
cmd = win32com.client.Dispatch(r'ADODB.Command')
cmd.ActiveConnection = connection
cmd.CommandText = "GRANT SELECT ON MSysObjects TO Admin;"
cmd.Execute()
connection.Execute(ACCESS_QUERY_META_INFO_CREATE)
connection.Close()

# connect with odbc to read the query meta info into pandas
connection_string = Constants.CONNECTION_STRING_ACCESS.format(database_path)
access_con = pyodbc.connect(connection_string)
access_cursor = access_con.cursor()

df = pd.read_sql(ACCESS_QUERY_META_INFO_READ, access_con)

# drop table after read
access_cursor.execute(ACCESS_QUERY_META_INFO_DROP)
access_cursor.commit

这似乎取决于MSysQueries中条目的顺序,这是胡说八道。查询文本取决于查询的创建方式,而不是其他方式。在visual builder中,这意味着将哪个列拖到哪个列。可以在任意方向创建连接。对于外部联接,根据拖动顺序,类似的操作可能导致
左联接
右联接
。类似地,
WHERE
子句的顺序取决于查询的创建方式。如果要检测导致使用不同文本执行相同的查询,则需要编写/获取SQL解析器。为了测试我的代码,我创建了一个空数据库,并从另一个数据库导入了查询。当我比较它们时,我得到了差异,因为连接的顺序已经改变了。奇怪的结果。所以我进去编辑代码来改变它。MSYS查询中没有差异。很奇怪。因此,我将代码更新为完全不同的内容,保存,然后重新更改。仍然以不同的顺序存储。听起来您正在以一种奇怪的方式导入查询。我使用的默认方法只是复制SQL。@ErikA进一步研究,结果发现在其中一个数据库中,表有一个主键,而在另一个数据库中没有。当我将主键添加到表中时,它更改了联接的存储顺序。非常奇怪的行为。“看起来您无法从python本身授予读取权限”-与其说是python,不如说是pyodbc。Microsoft为Jet/ACE数据库提供ODBC驱动程序和OLEDB提供程序。前者不能执行GRANT语句,而后者可以执行GRANT语句。