我有将数据从一个表插入到另一个表的功能
$BODY$
BEGIN
INSERT INTO backups.calls2 (uid,queue_id,connected,callerid2)
SELECT distinct (c.uid) ,c.queue_id,c.connected,c.callerid2
FROM public.calls c
WHERE c.connected is not null;
RETURN;
EXCEPTION WHEN unique_violation THEN NULL;
END;
$BODY$
表的结构:
CREATE TABLE backups.nc_calls_id
(
uid character(30) NOT NULL,
queue_id integer,
callerid2 text,
connected timestamp without time zone,
id serial NOT NULL,
CONSTRAINT calls2_pkey PRIMARY KEY (uid)
)
WITH (
OIDS=FALSE
);
当我第一次执行这个查询时,一切正常,200000 行被插入到具有唯一 ID 的新表中。 但是现在,当我再次执行它时,没有插入任何行
最佳答案
从给出的相当简约的描述(没有 PostgreSQL 版本,没有 CREATE FUNCTION
语句显示参数等,没有其他表结构,没有函数调用)我猜你正在尝试做一个合并,仅当行不存在时才插入行,如果行已存在则跳过行。
如果任何行已经存在,上面的函数将跳过所有行。
您需要使用循环在单个 BEGIN ... EXCEPTION
block 中执行插入(慢)或 LOCK
表并执行 INSERT INTO ... SELECT ... FROM newtable WHERE NOT EXISTS (SELECT 1 FROM oldtable where oldtable.key = newtable.key)
.
INSERT INTO ... SELECT ... WHERE NOT EXISTS
方法会执行得更好,但如果同时运行多个方法或如果同时向目标表中插入任何其他内容,则会失败时间。 LOCK
在运行目标表之前对其进行锁定将确保它是安全的。
PL/PgSQL 循环BEGIN ... EXCEPTION
方法乍一看听起来 不错而且安全。然后你想一下当你同时运行其中两个时会发生什么。一个会先插入一些键,一个会先插入其他键,所以它们之间有一个值的拆分。没关系,它们一起构成了全套。但是,如果其中只有一个提交而另一个由于某种原因失败了怎么办?您将得到一个有趣的稀疏插入结果。出于这个原因,如果也使用这种方法,最好锁定目标表......在这种情况下,您还不如使用效率更高的单遍 INSERT
和基于子查询的唯一性违规检查。
关于Postgresql 函数无法按预期使用 INSERT INTO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17007929/