pyodbc - 从MS Access(MDB)数据库读取主键

3

当我尝试使用cursor.primaryKeys("tablename")时,会出现异常:

错误:('IM001','[IM001] [Microsoft][ODBC驱动程序管理器]驱动程序不支持此功能(0)(SQLPrimaryKeys)')

list(cursor.columns(table='tablename'))也无法显示主键。


这是一个在.NET中的解决方案:http://stackoverflow.com/questions/862749/how-to-get-the-primary-key-of-an-ms-access-table-in-c-sharp - denfromufa
2个回答

5

对于Access ODBC,我们通常可以通过pyodbc cursor对象的.statistics()方法获得主键列:

*通常意味着不是所有情况都适用。
crsr = conn.cursor()
table_name = 'MyTable'
# dict comprehension: {ordinal_position: col_name}
pk_cols = {row[7]: row[8] for row in crsr.statistics(table_name) if row[5]=='PrimaryKey'}
print(pk_cols)  # e.g., {1: 'InvID', 2: 'LineItem'}

*编辑:此方法假设表的主键索引命名为PrimaryKey。如果使用MS Access表构建器(GUI)创建表格,则为真,但如果使用DDL(即CREATE TABLE…)创建表格,则不是真的。在这些情况下,主键索引将具有像Index_EA5344E1_0942_445C这样的名称,因此上述方法将无法工作,但我们可以使用ACE DAO:

import win32com.client  # needs `pip install pywin32`


def get_access_primary_key_columns(db_path, table_name):
    db_engine = win32com.client.Dispatch("DAO.DBEngine.120")
    db = db_engine.OpenDatabase(db_path)
    tbd = db.TableDefs(table_name)
    for idx in tbd.Indexes:
        if idx.Primary:
            return [fld.Name for fld in idx.Fields]


if __name__ == "__main__":
    print(
        get_access_primary_key_columns(
            r"C:\Users\Public\Database1.accdb", "team"
        )
    )
    # ['city', 'prov']

“OleDbSchemaGuid.Primary_Keys”和“Columns [“COLUMN_NAME”] .Ordinal”的等效物是什么?目前,您已经从统计数据中硬编码了索引5、7和8。 - denfromufa
2
@denfromufa - 这些是在光标对象.statistics方法文档中定义的列索引。你可以创建自己的变量,例如ordinal_position_col = 7,但除了使代码更加自我说明外,它与原来的代码没有什么区别。 - Gord Thompson
2
实际上,它是由微软的ODBC驱动程序定义的:https://msdn.microsoft.com/zh-cn/library/ms711022(VS.85).aspx - denfromufa
@denfromufa - 很好的参考。谢谢你的发布。 - Gord Thompson

2

这里有一个使用pythonnet和Oledb Jet驱动程序的解决方案。请注意,这不会保留主键列的顺序:

import clr
import System
import System.Data.OleDb
from System.Data.OleDb import OleDbSchemaGuid

def getKeyNames(tableName, mdbname):
    conn = System.Data.OleDb.OleDbConnection()
    conn.ConnectionString = ("Provider=Microsoft.Jet.OLEDB.4.0;"
                         "Data source={}".format(mdbname))
    conn.Open()
    returnList=[]
    mySchema = (conn).GetOleDbSchemaTable(OleDbSchemaGuid.Primary_Keys,
        [None, None, tableName])
    columnOrdinalForName = mySchema.Columns["COLUMN_NAME"].Ordinal
    for r in mySchema.Rows:
        returnList.append(r.ItemArray[columnOrdinalForName])
        conn.Close()
    return returnList

getKeyNames(table_name,mdbname)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接