code_junkie

How to reset postgres' primary key sequence when it falls out of sync?

Nov 11th, 2011
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.81 KB | None | 0 0
  1. // Login to psql and run the following
  2. // What is the result?
  3. SELECT MAX(id) FROM your_table;
  4.  
  5. // Then run...
  6. // This should be higher than the last result.
  7. SELECT nextval('your_table_id_seq');
  8.  
  9. // If it's not higher... run this to try and fix it. (run a quick pg_dump first...)
  10. SELECT setval('your_table_id_seq', (SELECT MAX(id) FROM your_table)+1);
  11.  
  12. CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text, columnname text, sequence_name text) RETURNS "pg_catalog"."void" AS
  13.  
  14. $body$
  15. DECLARE
  16. BEGIN
  17.  
  18. EXECUTE 'SELECT setval( ''' || sequence_name || ''', ' || '(SELECT MAX(' || columnname || ') FROM ' || tablename || ')' || '+1)';
  19.  
  20.  
  21.  
  22. END;
  23.  
  24. $body$ LANGUAGE 'plpgsql';
  25.  
  26.  
  27. 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%';
  28.  
  29. SELECT pg_catalog.setval(pg_get_serial_sequence('table_name', 'id'), (SELECT MAX(id) FROM table_name)+1);
  30.  
  31. CREATE OR REPLACE FUNCTION sequence_max_value(oid) RETURNS bigint
  32. VOLATILE STRICT LANGUAGE plpgsql AS $$
  33. DECLARE
  34. tabrelid oid;
  35. colname name;
  36. r record;
  37. newmax bigint;
  38. BEGIN
  39. FOR tabrelid, colname IN SELECT attrelid, attname
  40. FROM pg_attribute
  41. WHERE (attrelid, attnum) IN (
  42. SELECT adrelid::regclass,adnum
  43. FROM pg_attrdef
  44. WHERE oid IN (SELECT objid
  45. FROM pg_depend
  46. WHERE refobjid = $1
  47. AND classid = 'pg_attrdef'::regclass
  48. )
  49. ) LOOP
  50. FOR r IN EXECUTE 'SELECT max(' || quote_ident(colname) || ') FROM ' || tabrelid::regclass LOOP
  51. IF newmax IS NULL OR r.max > newmax THEN
  52. newmax := r.max;
  53. END IF;
  54. END LOOP;
  55. END LOOP;
  56. RETURN newmax;
  57. END; $$ ;
  58.  
  59. select relname, setval(oid, sequence_max_value(oid))
  60. from pg_class
  61. where relkind = 'S';
  62.  
  63. select relname, setval(pg_class.oid, sequence_max_value(pg_class.oid))
  64. from pg_class, pg_namespace
  65. where pg_class.relnamespace = pg_namespace.oid and
  66. nspname = 'public' and
  67. relkind = 'S';
  68.  
  69. alvherre=# d baz
  70. Tabla «public.baz»
  71. Columna | Tipo | Modificadores
  72. ---------+---------+------------------------------------------------
  73. a | integer | default nextval(('foo_a_seq'::text)::regclass)
  74.  
  75. alvherre=# alter table baz alter a set default nextval('foo_a_seq');
  76. ALTER TABLE
  77.  
  78. alvherre=# d baz
  79. Tabla «public.baz»
  80. Columna | Tipo | Modificadores
  81. ---------+---------+----------------------------------------
  82. a | integer | default nextval('foo_a_seq'::regclass)
  83.  
  84. CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text) RETURNS "pg_catalog"."void" AS
  85. $body$
  86. DECLARE
  87. BEGIN
  88. EXECUTE 'SELECT setval( '''
  89. || tablename
  90. || '_id_seq'', '
  91. || '(SELECT id + 1 FROM "'
  92. || tablename
  93. || '" ORDER BY id DESC LIMIT 1), false)';
  94. END;
  95. $body$ LANGUAGE 'plpgsql';
  96.  
  97. select sequence_name, reset_sequence(split_part(sequence_name, '_id_seq',1)) from information_schema.sequences
  98. where sequence_schema='public';
  99.  
  100. CREATE OR REPLACE FUNCTION rebuilt_sequence() RETURNS integer as ''
  101. DECLARE
  102. sequencedefs RECORD;
  103. c integer ;
  104. BEGIN
  105. FOR sequencedefs IN Select
  106. constraint_column_usage.table_name as tablename,
  107. constraint_column_usage.table_name as tablename,
  108. constraint_column_usage.column_name as columnname,
  109. replace(replace(columns.column_default,'''::regclass)',''),'nextval(''','') as sequencename
  110. from information_schema.constraint_column_usage,
  111. information_schema.columns
  112. where constraint_column_usage.table_schema ='public' AND
  113. columns.table_schema = 'public' AND
  114. columns.table_name=constraint_column_usage.table_name AND
  115. constraint_column_usage.column_name = columns.column_name AND
  116. columns.column_default is not null
  117. LOOP
  118. EXECUTE 'select max('||sequencedefs.columnname||') from ' || sequencedefs.tablename INTO c;
  119.  
  120. IF c is not null THEN
  121. c = c+ 1;
  122. EXECUTE 'alter sequence ' || sequencedefs.sequencename ||' restart with ' ||c;
  123. END LOOP;
  124. RETURN 1;
  125. END;
  126. $$ LANGUAGE plpgsql;
  127.  
  128. select sequence_name, --PG_CLASS.relname, PG_ATTRIBUTE.attname
  129. reset_sequence(split_part(sequence_name, '_id_seq',1))
  130. from PG_CLASS
  131. join PG_ATTRIBUTE on PG_ATTRIBUTE.attrelid = PG_CLASS.oid
  132. join information_schema.sequences
  133. on information_schema.sequences.sequence_name = PG_CLASS.relname || '_' || PG_ATTRIBUTE.attname
  134. where sequence_schema='public';
  135.  
  136. drop function IF EXISTS rebuilt_sequences() RESTRICT;
  137. CREATE OR REPLACE FUNCTION rebuilt_sequences() RETURNS integer as
  138. $body$
  139. DECLARE sequencedefs RECORD; c integer ;
  140. BEGIN
  141. FOR sequencedefs IN Select
  142. constraint_column_usage.table_name as tablename,
  143. constraint_column_usage.table_name as tablename,
  144. constraint_column_usage.column_name as columnname,
  145. replace(replace(columns.column_default,'''::regclass)',''),'nextval(''','') as sequencename
  146. from information_schema.constraint_column_usage, information_schema.columns
  147. where constraint_column_usage.table_schema ='public' AND
  148. columns.table_schema = 'public' AND columns.table_name=constraint_column_usage.table_name
  149. AND constraint_column_usage.column_name = columns.column_name
  150. AND columns.column_default is not null
  151. LOOP
  152. EXECUTE 'select max('||sequencedefs.columnname||') from ' || sequencedefs.tablename INTO c;
  153. IF c is null THEN c = 0; END IF;
  154. IF c is not null THEN c = c+ 1; END IF;
  155. EXECUTE 'alter sequence ' || sequencedefs.sequencename ||' restart with ' || c;
  156. END LOOP;
  157.  
  158. RETURN 1; END;
  159. $body$ LANGUAGE plpgsql;
  160.  
  161. select rebuilt_sequences();
  162.  
  163. --drop function IF EXISTS reset_sequence (text,text) RESTRICT;
  164. CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text,columnname text) RETURNS bigint --"pg_catalog"."void"
  165. AS
  166. $body$
  167. DECLARE seqname character varying;
  168. c integer;
  169. BEGIN
  170. select tablename || '_' || columnname || '_seq' into seqname;
  171. EXECUTE 'SELECT max("' || columnname || '") FROM "' || tablename || '"' into c;
  172. if c is null then c = 0; end if;
  173. c = c+1; --because of substitution of setval with "alter sequence"
  174. --EXECUTE 'SELECT setval( "' || seqname || '", ' || cast(c as character varying) || ', false)'; DOES NOT WORK!!!
  175. EXECUTE 'alter sequence ' || seqname ||' restart with ' || cast(c as character varying);
  176. RETURN nextval(seqname)-1;
  177. END;
  178. $body$ LANGUAGE 'plpgsql';
  179.  
  180. select sequence_name, PG_CLASS.relname, PG_ATTRIBUTE.attname,
  181. reset_sequence(PG_CLASS.relname,PG_ATTRIBUTE.attname)
  182. from PG_CLASS
  183. join PG_ATTRIBUTE on PG_ATTRIBUTE.attrelid = PG_CLASS.oid
  184. join information_schema.sequences
  185. on information_schema.sequences.sequence_name = PG_CLASS.relname || '_' || PG_ATTRIBUTE.attname || '_seq'
  186. where sequence_schema='public';
  187.  
  188. BEGIN;
  189. CREATE OR REPLACE FUNCTION reset_sequence(_table_schema text, _tablename text, _columnname text, _sequence_name text)
  190. RETURNS pg_catalog.void AS
  191. $BODY$
  192. DECLARE
  193. BEGIN
  194. PERFORM 1
  195. FROM information_schema.sequences
  196. WHERE
  197. sequence_schema = _table_schema AND
  198. sequence_name = _sequence_name;
  199. IF FOUND THEN
  200. EXECUTE 'SELECT setval( ''' || _table_schema || '.' || _sequence_name || ''', ' || '(SELECT MAX(' || _columnname || ') FROM ' || _table_schema || '.' || _tablename || ')' || '+1)';
  201. ELSE
  202. RAISE WARNING 'SEQUENCE NOT UPDATED ON %.%', _tablename, _columnname;
  203. END IF;
  204. END;
  205. $BODY$
  206. LANGUAGE 'plpgsql';
  207.  
  208. SELECT reset_sequence(table_schema, table_name, column_name, table_name || '_' || column_name || '_seq')
  209. FROM information_schema.columns
  210. WHERE column_default LIKE 'nextval%';
  211.  
  212. DROP FUNCTION reset_sequence(_table_schema text, _tablename text, _columnname text, _sequence_name text) ;
  213. COMMIT;
Add Comment
Please, Sign In to add comment