插入空表时出现 psycopg2 UniqueViolation 错误
Posted
技术标签:
【中文标题】插入空表时出现 psycopg2 UniqueViolation 错误【英文标题】:psycopg2 UniqueViolation error while inserting in empty table 【发布时间】:2019-06-07 12:26:26 【问题描述】:假设我有这样定义的用户表:
CREATE TABLE user (
id SERIAL UNIQUE,
email character varying(254) NOT NULL UNIQUE,
username character varying(254) NOT NULL UNIQUE
)
并以这种方式定义它的触发器:
CREATE OR REPLACE FUNCTION insert_username() RETURNS
TRIGGER AS $insert_username$
BEGIN
NEW.username := SPLIT_PART(NEW.email, '@', 1);
RETURN NEW;
END;
$insert_username$ LANGUAGE plpgsql;
CREATE TRIGGER insert_username BEFORE INSERT OR UPDATE
ON user FOR EACH ROW EXECUTE
PROCEDURE insert_username();
然后使用 psycopg2 我试图用来自另一个数据库的数据填充这个表。这是我制作的迁移模块中的一段代码以及负责此操作的查询字符串:
from psycopg2.extras import execute_values
from data_migration.database import cursor
query = 'INSERT INTO user("id", "email") VALUES %s'
values = [[1, 'example1@email.com'], [2, 'example2@email.com']]
execute_values(cursor, query, values)
在我实施此触发器之前,它一直按预期工作。现在,当我从 postgres shell 插入单行或使用 psycopg2 时,它仍然可以正常工作,但它在 execute_values 上失败,并且即使表完全为空,也会出现 UniqueViolation 错误:
UniqueViolation: duplicate key value violates unique constraint "user_username_key"
DETAIL: Key (username)=(kjhmgfd) already exists.
它周围有更多的字段和代码,当然,我可以摆脱这个触发器并在 python 端做同样的事情。但我真的很想保留它。也许我遗漏了一些明显的东西,但我已经花了几个小时在上面,但仍然不知道它为什么会发生。如果有人可以帮助我找到它,那将非常有帮助。谢谢!
【问题讨论】:
从错误中,看起来可能有多个用户使用 kjhmgfd@* 。你能检查源数据吗? @Jeremy 是的,就是这样。谢谢 【参考方案1】:这似乎是我对源数据缺乏关注。我有一些用户在电子邮件中具有相同的本地部分但不同的域。感谢杰里米指出。最终以这种方式修改触发器:
CREATE OR REPLACE FUNCTION insert_username() RETURNS
TRIGGER AS $insert_username$
DECLARE
counter INTEGER := 0;
new_username VARCHAR(256);
attempt_username VARCHAR(256);
is_exists BOOLEAN;
BEGIN
CREATE OR REPLACE FUNCTION is_username_exists(un VARCHAR(256))
RETURNS BOOLEAN AS $$
DECLARE
is_row_exists BOOLEAN;
BEGIN
SELECT EXISTS(SELECT * FROM user WHERE username=un) INTO is_row_exists;
RETURN is_row_exists;
END;
$$ LANGUAGE plpgsql;
new_username := SPLIT_PART(NEW.email, '@', 1);
attempt_username := new_username;
LOOP
SELECT is_username_exists(attempt_username) INTO is_exists;
EXIT WHEN is_exists IS FALSE;
counter := counter + 1;
attempt_username := new_username || counter;
END LOOP;
NEW.username := attempt_username;
RETURN NEW;
END;
$insert_username$ LANGUAGE plpgsql;
CREATE TRIGGER insert_username BEFORE INSERT OR UPDATE
ON user FOR EACH ROW EXECUTE PROCEDURE insert_username();
【讨论】:
以上是关于插入空表时出现 psycopg2 UniqueViolation 错误的主要内容,如果未能解决你的问题,请参考以下文章
使用 psycopg2 在 python 中执行查询时出现“ProgrammingError:在或附近出现语法错误”
在 unix 上为 python 3.5 安装 psycopg2 包
使用 Python 在 Flask 中创建端点时出现问题 [重复]