Reputation: 11
I am trying to reflect a table using sqlalchemy
by executing:
PilotCycle = Table('PilotCycle', pr_meta, schema='dbo', autoload=True, autoload_with=pr_engine)
However, I receive an error: "ArgumentError: ForeignKeyConstraint with duplicate source column references are not supported."
I think I figured out what's causing this by inspecting the table's foreign keys.
from sqlalchemy import inspect
insp = inspect(pr_engine)
fks = insp.get_foreign_keys('PilotCycle')
print(fks)
This returns a list of dicts with each element being a foreign key constraint. I found one foreign key, 'FK_PilotCycle_Equipment'
, that has duplicate constrained columns (EquipmentID
) and duplicate referred columns (ID
). Here is the dict in the list that I am referring to:
{
'name': 'FK_PilotCycle_Equipment',
'constrained_columns': ['EquipmentID', 'EquipmentID'],
'referred_schema': None,
'referred_table': 'Equipment',
'referred_columns': ['ID', 'ID']
}
I have read only access to the database. How can I fix this?
Upvotes: 1
Views: 1724
Reputation: 11
I just spent a day wrangling the same issue and have at least traced its source, if not solved it.
This error is caused by two identically-named PRIMARY KEYS in the same database -- even if the Foreign Keys are in schemas and tables that have nothing to do with each other.
The root issue is the way in which the db inspection query is written in 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]``
If you replace MYTABLE
and MYSCHEMA
with the offending table in your DB, you should see a row come back that has the same constraint name but comes from a completely different table.
The following query will find all colliding Primary Key names in a DB:
select CONSTRAINT_NAME, count(*)
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS
where CONSTRAINT_TYPE = 'PRIMARY KEY'
group by CONSTRAINT_NAME
having count(*) > 1
Unfortunately, if you don't have access to change the DB DDL, I see no easy solution for this.
I've submitted both an issue and a PR with a fix to the SQLAlchemy bug:
If you're in a bind, you can probably take my PR and monkey-patch SQLAlchemy, although I haven't tried this myself.
Upvotes: 1