尝试添加UNIQUE约束,但告知已经存在

时间:2020-10-22 15:27:38

标签: python database postgresql psycopg2

我有一个包含数百个表的大型数据库。每个表具有功能上等效的结构:一列是唯一标识符,另一列是组成员身份指示符;也就是说,表中的每一行都有唯一的标识符,但是任何数量的行都可以具有相同的组成员身份指示符。这些表也是在同一架构中成对创建的,因此该数据库的命名方案为project_abbreviation.<name>_<suffix>;例如proj_abc.original_aproj_abc.original_b对。

我继承了这个数据库,当原始开发人员构造它时,他们在创建表时没有向唯一标识符列添加UNIQUE约束。结果,每当有人要更改给定表中的一行或一组行的组成员资格指示符时,如果表自创建以来没有被修改,则我必须在列上添加一个UNIQUE约束。我通过编程方式做到这一点:

@connect
def make_column_unique(self, cursor, connection, column, suffix):
    sql = f"ALTER TABLE {self._schema}.{self._table}_{suffix} "
    sql += f"ADD CONSTRAINT unique_{column} UNIQUE ({column});"

    cursor.execute(sql)
    connection.commit()

其中@connect是连接到数据库实例的装饰器函数,而cursorconnection参数分别是psycopg2 CursorConnection对象。然后,我在try / except块中调用它:

...

for suffix in ["a", "b"]:
    try:
        self.modify_table(...)
    except (Exception, psycopg2.DatabaseError) as e:
        self.make_column_unique("uid", suffix)
        self.modify_table(...)
...

这是self.modify_table的功能签名:

@connect
def modify_table(self, cursor, connection, data, suffix):
    sql = f"INSERT INTO {self._schema}.{self._table}_{suffix} (uid, group) "
    sql += "VALUES "

    zipped = list(zip(list(data["uid"]), list(data["group"])))
    row = 0

    for uid, group in zipped:
        row += 1
        sql += f"({uid},'{group}')" + ("," if row < len(zipped) else " ")

    sql += f"ON CONFLICT (uid) DO UPDATE "
    sql += "SET group = EXCLUDED.group;"

    cursor.execute(sql)
    connection.commit()

这种方法非常有效,可以正确修改表条目,并在需要设置约束时设置UNIQUE约束。

现在,当我尝试修改尚未修改的表时,出现一个There is no unique or exclusion constraint matching the ON CONFLICT specification错误,该错误开始了对make_column_unique的调用。但是,当程序尝试使提供的列唯一时,我返回了relation "unique_<column>" already exists错误。此外,这仅在后缀为a的表中发生,而不是后缀为b的表。我进入pgAdmin4进行验证,并且在具有后缀b的表,但是在数据库事务前后,具有后缀a的表没有约束:

无限制的pgAdmin数据库查看器

pgAdmin database viewer with no constraints

为什么只有一种类型的表会出现这些矛盾的错误?告诉我UNIQUE约束不存在对我来说没有意义,然后当我更改表以包含该约束时,被告知该约束已经存在。

1 个答案:

答案 0 :(得分:1)

这是我对这个问题可能给出的最愚蠢的答案。

事实证明,以我前任的无限智慧,他们决定将重复的值随机散布到本应唯一的列中。易于修复。