Python / Access NameError: name '' is not defined

Python / Access NameError: name '' is not defined

我正在尝试将一些旧的 Access VBA 代码重写为 Python,但我遇到了以下错误: NameError: 名称 'ERTZ6635' 未定义

旧VBA代码

 Set ConsTable = DB.OpenRecordset("SELECT * FROM table1")
 ConsCount = 87404
  If ConsCount > 0 Then
    ConsTable.MoveFirst
    For I = 1 To ConsCount
      Set ConsBlendTable = DB.OpenRecordset("SELECT * FROM table2 WHERE CONS_BATCH = " & Char34(ConsTable!Batch))

Python代码:

进口win32com.client

dbe = win32com.client.Dispatch("DAO.DBEngine.120")
db = dbe.OpenDatabase(r"C:\Users\xyz\Desktop\acess.accdb")
ConsTable = db.OpenRecordset("select * from table1")
ConsCount = 87404

if ConsCount>0:
    ConsTable.MoveFirst()
    for i in range(1, ConsCount):
        ConsBlendTable = db.OpenRecordset("SELECT * FROM table2 WHERE CONS_BATCH = " & eval(ConsTable.Fields["Batch"].Value))

而ERTZ6635的值为ConsTable.Fields["Batch"].Value

中的值

在 VBA 代码中,Char34() 可能是用户定义的函数,因为它不是 VBA 内置方法。然而,对于双引号的 ASCII table 中的第 34 个字符有一个常量 Chr34。因此,根据其名称,此方法可能会将输入参数值用双引号引起来。这很重要,因为您尝试用 eval.

翻译 Python

如此简单的答案是包含双引号,您可以在 Python.

中用 F 字符串插入双引号
sql = f"""SELECT * FROM table2 
          WHERE CONS_BATCH = "{ConsTable.Fields["Batch"].Value}"
       """
ConsBlendTable = db.OpenRecordset(sql)

但是,SQL 查询中的参数字符串插值 不可取 在任何语言中,包括 VBA 和 Python。除了安全和效率问题,如果值本身包含双引号,此代码仍然会出错。

相反,请考虑通过 QueryDefs.

在 MS Access SQL 引擎中支持的参数化

VBA (根据之前的 SQL 连接调整)

Dim qdef As QueryDef
...

Set ConsTable = DB.OpenRecordset("SELECT * FROM table1")

' PREPARED STATEMENT (NO DATA)
sql = "PARAMETERS batch_prm TEXT(255);" _
    & "SELECT * FROM table2 WHERE CONS_BATCH = batch_prm"

ConsTable.MoveFirst
Do While Not ConsTable.EOF
   Set qdef = DB.CreateQueryDef("", sql)
   qdef!batchprm = ConsTable!Batch              ' BIND PARAMETER
   Set ConsBlendTable = qdef.OpenRecordset()    ' OPEN RECORDSET VIA QUERYDEF

    ...

    ConsBlendTable.Close
    ConsTable.MoveNext
Loop

ConsTable.Close

'RELEASE RESOURCES
Set ConsBlendTable = Nothing: Set ConsTable = Nothing
Set qdef = Nothing: Set DB = Nothing

Python (使用 try/except 进行正确的 COM 处理)

因此在Python中,我们类似地与QueryDef对象进行交互。下面使用传统的 DAO 循环遍历记录集中的每条记录(即 Do While Not rst.EOF 的翻译)。

import win32com.client

try:
    dbe = win32com.client.Dispatch("DAO.DBEngine.120")
    db = dbe.OpenDatabase(r"C:\Users\xyz\Desktop\acess.accdb")

    ConsTable = db.OpenRecordset("SELECT * FROM table1")

    # PREPARED STATEMENT
    sql = """PARAMETERS batch_prm TEXT(255);
             SELECT * FROM table2 WHERE CONS_BATCH = batch_prm
          """

    ConsTable.MoveFirst()

    while ConsTable.EOF == False:
        qdef = db.CreateQueryDef("", sql)
        # BIND PARAMETER
        qdef.Parameters["batch_prm"].Value = ConsTable.Fields["Batch"].Value 

        # OPEN RECORDSET VIA QUERYDEF 
        ConsBlendTable = qdef.OpenRecordset()

        ...

        ConsBlendTable.Close()
        ConsTable.MoveNext()
                    
    ConsTable.Close()
        
except Exception as e:
    print(e)
    
finally:
    # RELEASE RESOURCES
    ConsBlendTable = None; ConsTable = None
    qdef = None; db = None; dbe = None
    del ConsBlendTable; del ConsTable; del qdef; del db; del dbe

最后,我必须注意。不要直接翻译 VBA,而是使用 Python 的 DB-API,因为它可以直接查询没有 DAO 或 COM 对象的 MS Access 数据库,特别是维护良好的:pyodbc.并且 运行 使用 JOIN 而不是通过 WHERE 的迭代循环。是的,pyodbc 支持 parameters? qmarks。

import pyodbc

dbname = r"C:\Users\xyz\Desktop\acess.accdb"
constr = f"DRIVER={{Microsoft Access Driver (*.mdb, *.accdb)}};DBQ={dbname};"

conn = pyodbc.connect(constr)
cur = conn.cursor()

sql = """SELECT t1.Batch, t2.CONS_BATCH, ... 
         FROM table1 t1
         INNER JOIN tbale2 t2
             ON t1.Batch = t2.CONS_BATCH 
      """       

cur.execute(sql)

for row in cur.fetchall():
    ...

cur.close()
conn.close()