SQLAlchemy表反射 - 删除重复的源列引用

时间:2017-11-09 15:19:01

标签: python sqlalchemy

我试图通过执行 sqlalchemy 来反映一个表:

PilotCycle = Table('PilotCycle', pr_meta, schema='dbo', autoload=True, autoload_with=pr_engine)

但是,我收到错误消息: "ArgumentError: ForeignKeyConstraint with duplicate source column references are not supported."

我想我通过检查表的外键找出导致这种情况的原因。

from sqlalchemy import inspect
insp = inspect(pr_engine)
fks = insp.get_foreign_keys('PilotCycle')
print(fks)

这将返回一个dicts列表,其中每个元素都是外键约束。我找到了一个外键'FK_PilotCycle_Equipment',它有重复的约束列(EquipmentID)和重复的引用列(ID)。这是我所指的列表中的字典:

{
    'name': 'FK_PilotCycle_Equipment', 
    'constrained_columns': ['EquipmentID', 'EquipmentID'],
    'referred_schema': None,
    'referred_table': 'Equipment',
    'referred_columns': ['ID', 'ID']
}

我只读取了对数据库的访问权限。我怎样才能解决这个问题?

1 个答案:

答案 0 :(得分:0)

我花了整整一天时间解决同一问题,并且至少追踪了它的来源,如果没有解决的话。

此错误是由同一数据库中的两个名称相同的PRIMARY KEY引起的-即使外键位于彼此无关的架构和表中。

根本问题是在dialects/mssql/base.py中编写数据库检查查询的方式:

```SELECT [C].[COLUMN_NAME], 
[R].[TABLE_SCHEMA], 
[R].[TABLE_NAME], 
[R].[COLUMN_NAME], 
[INFORMATION_SCHEMA].[REFERENTIAL_CONSTRAINTS].[CONSTRAINT_NAME], 
[INFORMATION_SCHEMA].[REFERENTIAL_CONSTRAINTS].[MATCH_OPTION], 
[INFORMATION_SCHEMA].[REFERENTIAL_CONSTRAINTS].[UPDATE_RULE], 
[INFORMATION_SCHEMA].[REFERENTIAL_CONSTRAINTS].[DELETE_RULE] 
FROM [INFORMATION_SCHEMA].[KEY_COLUMN_USAGE] AS [C], [INFORMATION_SCHEMA].[KEY_COLUMN_USAGE] AS [R], [INFORMATION_SCHEMA].[REFERENTIAL_CONSTRAINTS] 
WHERE [C].[TABLE_NAME] = CAST('MYTABLE' AS NVARCHAR(max)) AND [C].[TABLE_SCHEMA] = CAST('MYSCHEMA' AS NVARCHAR(max)) AND [INFORMATION_SCHEMA].[REFERENTIAL_CONSTRAINTS].[CONSTRAINT_SCHEMA] = [C].[TABLE_SCHEMA] AND [C].[CONSTRAINT_NAME] = [INFORMATION_SCHEMA].[REFERENTIAL_CONSTRAINTS].[CONSTRAINT_NAME] AND [R].[CONSTRAINT_NAME] = [INFORMATION_SCHEMA].[REFERENTIAL_CONSTRAINTS].[UNIQUE_CONSTRAINT_NAME] AND [C].[ORDINAL_POSITION] = [R].[ORDINAL_POSITION] ORDER BY [INFORMATION_SCHEMA].[REFERENTIAL_CONSTRAINTS].[CONSTRAINT_NAME], [R].[ORDINAL_POSITION]``

如果将MYTABLEMYSCHEMA替换为数据库中有问题的表,则应该看到返回的行具有相同的约束名称,但来自完全不同的表。

以下查询将在数据库中找到所有冲突的主键名称:

    select CONSTRAINT_NAME, count(*)
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS
where CONSTRAINT_TYPE = 'PRIMARY KEY'
group by CONSTRAINT_NAME
having count(*) > 1

不幸的是,如果您无权更改DB DDL,那么我认为没有简单的解决方案。

我同时提交了问题和PR,并修复了SQLAlchemy错误:

如果您处于绑定状态,尽管我自己没有尝试过,但您可能可以使用我的PR和猴子补丁SQLAlchemy。