【问题标题】:pyodbc - read primary keys from MS Access (MDB) databasepyodbc - 从 MS Access (MDB) 数据库中读取主键
【发布时间】:2016-10-09 07:12:54
【问题描述】:

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

Error: ('IM001', '[IM001] [Microsoft][ODBC Driver Manager] Driver does not support this function (0) (SQLPrimaryKeys)')

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

【问题讨论】:

标签: python sql database ms-access pyodbc


【解决方案1】:

对于 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_KeysColumns["COLUMN_NAME"].Ordinal 的等价物是什么?现在,您有来自统计数据的硬编码索引 5、7 和 8。
  • @denfromufa - 这些是cursor object.statistics 方法的文档中定义的列索引。您可以创建自己的变量,例如,ordinal_position_col = 7,但除了使代码更具自我记录性之外,它还相当于同样的事情。
  • 其实是由微软的ODBC驱动定义的:msdn.microsoft.com/en-us/library/ms711022(VS.85).aspx
  • @denfromufa - 很好的参考。感谢您发布它。
【解决方案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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多