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()
我正在尝试将一些旧的 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.
中用 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()