首页 > 解决方案 > 当 Access 使用 python 具有“Nz”表达式时,从 MS Access 导出到 Excel

问题描述

我有一个要导出到 excel 的访问表,但访问表(以及它调用的一些表)使用“Nz”表达式。我尝试用 IIf(IsNull( 甚至合并,但我似乎无法得到任何工作。我知道 pyodbc 访问驱动程序不支持他的 Nz 表达式,所以我试图找出解决方法。此外,我无权对 Access 数据库进行任何更改(这可能是最简单的解决方案。

另一个问题是连接中的某些列也有 NZ 表达式。对于脚本遇到的任何 Nz 表达式,可能会给出一个总值为 0 的东西?我不太使用 sql,所以这可能很容易,但我无法弄清楚如何。

我已经在没有 Nz 表达式的表上运行代码并且它可以工作,所以我知道驱动程序/cnxn 是正确的。

import pyodbc
import pandas as pd

ly_rep_temp_path = r"C:\examplePath\msAccessFile.accdb"
temp_path = r"C:\example\temoraryStorage"


driver = '{Microsoft Access Driver (*.mdb, *.accdb)}'


cnxn = pyodbc.connect(Driver=driver, DBQ=ly_rep_temp_path)


sql = """
SELECT rep.old, rep.new, Left(Nz([oldI].[mName],""),10) AS oldM, Left(Nz([newI].[mName],""),10) AS newM, oldI.primary AS oldS, newI.primary AS newS, oldI.primaryMR AS oldR, newI.primaryM AS newR,
FROM export_byI INNER JOIN ((rep INNER JOIN availableI AS oldI ON rep.olIs = oldI.isI) INNER JOIN availableI AS newI ON rep.nIsI = newI.isI) ON export_byI.IstI = rep.nwIsI
ORDER BY rep.nwIsI;
"""

crsr = cnxn.execute(sql)
for row in crsr.fetchall():
    lpd_df = pd.read_sql(sql, cnxn)
    print(lpd_df.columns)
    lpd_df.to_excel(temp_path + '/zFinal.xlsx')
    full_export_path = (temp_path + '/zFinal.xlsx')
    # return full_export_path
crsr.close()
cnxn.close()

运行代码时出现以下错误:“pyodbc.ProgrammingError: ('42000', “[42000] [Microsoft][ODBC Microsoft Access Driver] Undefined function 'Nz' in expression. (-3102) (SQLExecDirectW)” )"

标签: pythonms-accesspyodbc

解决方案


因此,如果我们有一个名为 [Donor] 的表

DonorID  DonorName  Comments     
-------  ---------  -------------
      1  Gord       cheapskate   
      2  Bill                    
      3  Marsha     Jan's nemesis

和一个名为 [query1] 的已保存查询,它使用Nz()

SELECT Donor.DonorID, Donor.DonorName, Nz([Comments],"(no comment)") AS txt
FROM Donor;

这会在 Microsoft Access 应用程序本身中产生以下内容

DonorID  DonorName  txt          
-------  ---------  -------------
      1  Gord       cheapskate   
      2  Bill       (no comment) 
      3  Marsha     Jan's nemesis

如果我们尝试crsr.execute("SELECT * FROM query1")在 pyodbc 中做,我们会得到

"pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC Microsoft Access Driver] 表达式中未定义函数'Nz'。(-3102)

因为Nz()不是 Access 数据库引擎 (ACE) 的内置功能;它是 VBA 表达式引擎的一部分。因此,为了从 Python 执行该查询,我们需要使用pywin32和 COM 自动化来运行 MSACCESS.EXE 的实例并以这种方式执行查询:

"""
requires: pip install pywin32
"""
import win32com.client

# ACE.DAO constants
dbOpenDynaset = 2

msa = win32com.client.Dispatch("Access.Application")
msa.OpenCurrentDatabase(r"C:\Users\Public\Database1.accdb")
db = msa.CurrentDb()
rst = db.OpenRecordset("SELECT * FROM query1", dbOpenDynaset)
while not rst.EOF:
    print(rst.Fields("txt").Value)
    rst.MoveNext()
"""console output:
cheapskate
(no comment)
Jan's nemesis
"""
msa.Quit()

编辑:如果要将查询导出到 Excel,可以直接从Access.Application实例中执行此操作:

acExport = 1
acSpreadsheetTypeExcel12Xml = 10
msa.DoCmd.TransferSpreadsheet(
    acExport, acSpreadsheetTypeExcel12Xml, "query1", r"C:\__tmp\test.xlsx"
)
msa.Quit()

推荐阅读