冲突“ cool name”->“ cool name 1”上的增量文本列

时间:2019-11-20 21:23:58

标签: sql postgresql

我在表上有一个唯一列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')?

2 个答案:

答案 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个后缀,直到它放弃。