我正在编写迁移脚本来迁移数据库。考虑到不同的数据库在表中可以有n个不同的列,我必须通过递增主键来复制行。我无法在查询中编写每一列。如果我只是复制该行,那么我将收到重复的密钥错误。
Query: INSERT INTO table_name SELECT * FROM table_name WHERE id=255;
ERROR: duplicate key value violates unique constraint "table_name_pkey"
DETAIL: Key (id)=(255) already exist
在这里,我不必提及所有列名称。我可以通过*来选择所有列。但是,同时我也遇到了重复的密钥错误。
这个问题的解决方案是什么?任何帮助,将不胜感激。提前谢谢。
答案 0 :(得分:1)
如果您愿意输入所有列名,可以写
INSERT INTO table_name (
pri_key
,col2
,col3
)
SELECT (
SELECT MAX(pri_key) + 1
FROM table_name
)
,col2
,col3
FROM table_name
WHERE id = 255;
其他选项(不键入所有列,但您知道主键)是CREATE
临时表,更新它并在事务中重新插入。
BEGIN;
CREATE TEMP TABLE temp_tab ON COMMIT DROP AS SELECT * FROM table_name WHERE id=255;
UPDATE temp_tab SET pri_key_col = ( select MAX(pri_key_col) + 1 FROM table_name );
INSERT INTO table_name select * FROM temp_tab;
COMMIT;
答案 1 :(得分:1)
这只是一个DO块,但您可以创建一个函数,将表名等内容作为参数。
设定:
CREATE TABLE public.t1 (a TEXT, b TEXT, c TEXT, id SERIAL PRIMARY KEY, e TEXT, f TEXT);
INSERT INTO public.t1 (e) VALUES ('x'), ('y'), ('z');
重复没有主键列的值的代码:
DO $$
DECLARE
_table_schema TEXT := 'public';
_table_name TEXT := 't1';
_pk_column_name TEXT := 'id';
_columns TEXT;
BEGIN
SELECT STRING_AGG(column_name, ',')
INTO _columns
FROM information_schema.columns
WHERE table_name = _table_name
AND table_schema = _table_schema
AND column_name <> _pk_column_name;
EXECUTE FORMAT('INSERT INTO %1$s.%2$s (%3$s) SELECT %3$s FROM %1$s.%2$s', _table_schema, _table_name, _columns);
END $$
它创建并运行的查询是:INSERT INTO public.t1 (a,b,c,e,f) SELECT a,b,c,e,f FROM public.t1
。它选择了除PK之外的所有列。您可以将此代码放在一个函数中,并将其用于您想要的任何表,或者只是像这样使用它并为任何表编辑它。