我遇到了一个问题,我的主键序列与我的表行不同步。
也就是说,当我插入一个新行时,我得到一个重复的键错误,因为在串行数据类型中隐含的序列返回一个已经存在的数字。
这似乎是由于导入/恢复没有正确地维护序列造成的。
我遇到了一个问题,我的主键序列与我的表行不同步。
也就是说,当我插入一个新行时,我得到一个重复的键错误,因为在串行数据类型中隐含的序列返回一个已经存在的数字。
这似乎是由于导入/恢复没有正确地维护序列造成的。
当前回答
所以我可以告诉你,在这个帖子里没有足够的意见或重新发明的轮子,所以我决定让事情变得有趣。
下面是一个程序:
关注(仅影响)与表相关的序列 适用于串行和生成的AS身份列 适用于good_column_names和“BAD_column_123”名称 如果表为空,则自动分配相应序列定义的起始值 允许只影响特定的序列(在schema.table.column表示法中) 有预览模式
CREATE OR REPLACE PROCEDURE pg_reset_all_table_sequences(
IN commit_mode BOOLEAN DEFAULT FALSE
, IN mask_in TEXT DEFAULT NULL
) AS
$$
DECLARE
sql_reset TEXT;
each_sec RECORD;
new_val TEXT;
BEGIN
sql_reset :=
$sql$
SELECT setval(pg_get_serial_sequence('%1$s.%2$s', '%3$s'), coalesce(max("%3$s"), %4$s), false) FROM %1$s.%2$s;
$sql$
;
FOR each_sec IN (
SELECT
quote_ident(table_schema) as table_schema
, quote_ident(table_name) as table_name
, column_name
, coalesce(identity_start::INT, seqstart) as min_val
FROM information_schema.columns
JOIN pg_sequence ON seqrelid = pg_get_serial_sequence(quote_ident(table_schema)||'.'||quote_ident(table_name) , column_name)::regclass
WHERE
(is_identity::boolean OR column_default LIKE 'nextval%') -- catches both SERIAL and IDENTITY sequences
-- mask on column address (schema.table.column) if supplied
AND coalesce( table_schema||'.'||table_name||'.'||column_name = mask_in, TRUE )
)
LOOP
IF commit_mode THEN
EXECUTE format(sql_reset, each_sec.table_schema, each_sec.table_name, each_sec.column_name, each_sec.min_val) INTO new_val;
RAISE INFO 'Resetting sequence for: %.% (%) to %'
, each_sec.table_schema
, each_sec.table_name
, each_sec.column_name
, new_val
;
ELSE
RAISE INFO 'Sequence found for resetting: %.% (%)'
, each_sec.table_schema
, each_sec.table_name
, each_sec.column_name
;
END IF
;
END LOOP;
END
$$
LANGUAGE plpgsql
;
预览:
调用pg_reset_all_table_sequences ();
提交:
调用pg_reset_all_table_sequences(真正的);
只指定你的目标表:
调用pg_reset_all_table_sequences(“schema.table.column”);
其他回答
所以我可以告诉你,在这个帖子里没有足够的意见或重新发明的轮子,所以我决定让事情变得有趣。
下面是一个程序:
关注(仅影响)与表相关的序列 适用于串行和生成的AS身份列 适用于good_column_names和“BAD_column_123”名称 如果表为空,则自动分配相应序列定义的起始值 允许只影响特定的序列(在schema.table.column表示法中) 有预览模式
CREATE OR REPLACE PROCEDURE pg_reset_all_table_sequences(
IN commit_mode BOOLEAN DEFAULT FALSE
, IN mask_in TEXT DEFAULT NULL
) AS
$$
DECLARE
sql_reset TEXT;
each_sec RECORD;
new_val TEXT;
BEGIN
sql_reset :=
$sql$
SELECT setval(pg_get_serial_sequence('%1$s.%2$s', '%3$s'), coalesce(max("%3$s"), %4$s), false) FROM %1$s.%2$s;
$sql$
;
FOR each_sec IN (
SELECT
quote_ident(table_schema) as table_schema
, quote_ident(table_name) as table_name
, column_name
, coalesce(identity_start::INT, seqstart) as min_val
FROM information_schema.columns
JOIN pg_sequence ON seqrelid = pg_get_serial_sequence(quote_ident(table_schema)||'.'||quote_ident(table_name) , column_name)::regclass
WHERE
(is_identity::boolean OR column_default LIKE 'nextval%') -- catches both SERIAL and IDENTITY sequences
-- mask on column address (schema.table.column) if supplied
AND coalesce( table_schema||'.'||table_name||'.'||column_name = mask_in, TRUE )
)
LOOP
IF commit_mode THEN
EXECUTE format(sql_reset, each_sec.table_schema, each_sec.table_name, each_sec.column_name, each_sec.min_val) INTO new_val;
RAISE INFO 'Resetting sequence for: %.% (%) to %'
, each_sec.table_schema
, each_sec.table_name
, each_sec.column_name
, new_val
;
ELSE
RAISE INFO 'Sequence found for resetting: %.% (%)'
, each_sec.table_schema
, each_sec.table_name
, each_sec.column_name
;
END IF
;
END LOOP;
END
$$
LANGUAGE plpgsql
;
预览:
调用pg_reset_all_table_sequences ();
提交:
调用pg_reset_all_table_sequences(真正的);
只指定你的目标表:
调用pg_reset_all_table_sequences(“schema.table.column”);
这将重置所有来自public的序列,不假设表或列名。在8.4版上测试
CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text, columnname text, sequence_name text)
RETURNS "pg_catalog"."void" AS
$body$
DECLARE
BEGIN
EXECUTE 'SELECT setval( ''' || sequence_name || ''', ' || '(SELECT MAX(' || columnname ||
') FROM ' || tablename || ')' || '+1)';
END;
$body$ LANGUAGE 'plpgsql';
SELECT table_name || '_' || column_name || '_seq',
reset_sequence(table_name, column_name, table_name || '_' || column_name || '_seq')
FROM information_schema.columns where column_default like 'nextval%';
只需运行以下命令:
SELECT setval('my_table_seq', (SELECT max(id) FROM my_table));
如果您在加载自定义SQL数据进行初始化时看到此错误,另一种避免此错误的方法是:
而不是写:
INSERT INTO book (id, name, price) VALUES (1 , 'Alchemist' , 10),
从初始数据中删除id(主键)
INSERT INTO book (name, price) VALUES ('Alchemist' , 10),
这使Postgres序列保持同步!
-- Login to psql and run the following
-- What is the result?
SELECT MAX(id) FROM your_table;
-- Then run...
-- This should be higher than the last result.
SELECT nextval('your_table_id_seq');
-- If it's not higher... run this set the sequence last to your highest id.
-- (wise to run a quick pg_dump first...)
BEGIN;
-- protect against concurrent inserts while you update the counter
LOCK TABLE your_table IN EXCLUSIVE MODE;
-- Update the sequence
SELECT setval('your_table_id_seq', COALESCE((SELECT MAX(id)+1 FROM your_table), 1), false);
COMMIT;
来源- Ruby论坛