我在表上有一个唯一列display_name
。插入新行时,我想执行以下ON CONFLICT (display_name)
:将数字附加到display_name
值上,以使其现在唯一。
例如在postgres 10中,
CREATE TABLE some_table (
id SERIAL NOT NULL PRIMARY KEY,
display_name text UNIQUE
);
INSERT INTO some_table (display_name) VALUES ('cool name');
INSERT INTO some_table (display_name) VALUES ('cool name')
ON CONFLICT (display_name) ....
-- 'cool name' is a duplicate here, can I somehow increment a suffix
-- here until it is a unique value (like 'cool name 1')?
答案 0 :(得分:3)
不可能在ON CONFLICT
子句中插入行(您只能更新现有行),因此无法使用该构造。使用plpgsql,例如
do $$
declare new_str text := 'cool name';
begin
insert into some_table (display_name)
values (new_str);
exception when unique_violation then
insert into some_table (display_name)
select format('%s %s',
new_str,
(select coalesce(nullif(regexp_replace(display_name, '^.*?(\d+)$', '\1'), display_name), '0')::int+ 1
from some_table
where left(display_name, length(new_str)) = new_str
order by 1 desc
limit 1)
);
end $$;
db<>fiddle.中的实时演示
答案 1 :(得分:3)
ON CONFLICT DO UPDATE
将更新现有行,而不是要插入的新行。您需要做的是动态选择要插入的值,使其不存在:
INSERT INTO some_table (display_name)
SELECT name
FROM generate_series(0, 1000) num,
LATERAL (SELECT 'cool name' || CASE WHEN num = 0 THEN '' ELSE ' ' || num END AS name) AS t
WHERE NOT EXISTS (SELECT 1 FROM some_table WHERE display_name = name)
ORDER BY num
LIMIT 1;
(online demo)
这将尝试多达1000个后缀,直到它放弃。