Export specific rows from a PostgreSQL table as INSERT SQL script - sql
I have a database schema named: nyummy and a table named cimory:
create table nyummy.cimory (
id numeric(10,0) not null,
name character varying(60) not null,
city character varying(50) not null,
CONSTRAINT cimory_pkey PRIMARY KEY (id)
);
I want to export the cimory table's data as insert SQL script file. However, I only want to export records/data where the city is equal to 'tokyo' (assume city data are all lowercase).
How to do it?
It doesn't matter whether the solution is in freeware GUI tools or command line (although GUI tools solution is better). I had tried pgAdmin III, but I can't find an option to do this.
Create a table with the set you want to export and then use the command line utility pg_dump to export to a file:
create table export_table as
select id, name, city
from nyummy.cimory
where city = 'tokyo'
$ pg_dump --table=export_table --data-only --column-inserts my_database > data.sql
--column-inserts will dump as insert commands with column names.
--data-only do not dump schema.
As commented below, creating a view in instead of a table will obviate the table creation whenever a new export is necessary.
To export data only use COPY:
COPY (SELECT * FROM nyummy.cimory WHERE city = 'tokio') TO '/path/to/file.csv';
You can export a whole table, only selected columns, or the result of a query as demonstrated. No need to create a table explicitly.
You get a file with one table row per line as plain text (not INSERT commands). Smaller and faster than INSERT commands.
To import the same to another Postgres table of matching structure anywhere (columns in same order, data types compatible!):
COPY other_tbl FROM '/path/to/file.csv';
COPY writes and reads files local to the server, unlike client programs like pg_dump or psql which read and write files local to the client. If both run on the same machine, it doesn't matter much, but it does for remote connections.
There is also the \copy command of psql:
Performs a frontend (client) copy. This is an operation that runs an
SQL COPY command, but instead of the server reading or
writing the specified file, psql reads or writes the file and routes
the data between the server and the local file system. This means that
file accessibility and privileges are those of the local user, not the server, and no SQL superuser privileges are required.
Same syntax as above. Just replace COPY with \copy.
This is an easy and fast way to export a table to a script with pgAdmin manually without extra installations:
Right click on target table and select "Backup".
Select a file path to store the backup. As Format choose "Plain".
Open the tab "Dump Options #2" at the bottom and check "Use Column Inserts".
Click the Backup-button.
If you open the resulting file with a text reader (e.g. notepad++) you get a script to create the whole table. From there you can simply copy the generated INSERT-Statements.
This method also works with the technique of making an export_table as demonstrated in #Clodoaldo Neto's answer.
For my use-case I was able to simply pipe to grep.
pg_dump -U user_name --data-only --column-inserts -t nyummy.cimory | grep "tokyo" > tokyo.sql
SQL Workbench has such a feature.
After running a query, right click on the query results and choose "Copy Data As SQL > SQL Insert"
I tried to write a procedure doing that, based on #PhilHibbs codes, on a different way.
Please have a look and test.
CREATE OR REPLACE FUNCTION dump(IN p_schema text, IN p_table text, IN p_where text)
RETURNS setof text AS
$BODY$
DECLARE
dumpquery_0 text;
dumpquery_1 text;
selquery text;
selvalue text;
valrec record;
colrec record;
BEGIN
-- ------ --
-- GLOBAL --
-- build base INSERT
-- build SELECT array[ ... ]
dumpquery_0 := 'INSERT INTO ' || quote_ident(p_schema) || '.' || quote_ident(p_table) || '(';
selquery := 'SELECT array[';
<<label0>>
FOR colrec IN SELECT table_schema, table_name, column_name, data_type
FROM information_schema.columns
WHERE table_name = p_table and table_schema = p_schema
ORDER BY ordinal_position
LOOP
dumpquery_0 := dumpquery_0 || quote_ident(colrec.column_name) || ',';
selquery := selquery || 'CAST(' || quote_ident(colrec.column_name) || ' AS TEXT),';
END LOOP label0;
dumpquery_0 := substring(dumpquery_0 ,1,length(dumpquery_0)-1) || ')';
dumpquery_0 := dumpquery_0 || ' VALUES (';
selquery := substring(selquery ,1,length(selquery)-1) || '] AS MYARRAY';
selquery := selquery || ' FROM ' ||quote_ident(p_schema)||'.'||quote_ident(p_table);
selquery := selquery || ' WHERE '||p_where;
-- GLOBAL --
-- ------ --
-- ----------- --
-- SELECT LOOP --
-- execute SELECT built and loop on each row
<<label1>>
FOR valrec IN EXECUTE selquery
LOOP
dumpquery_1 := '';
IF not found THEN
EXIT ;
END IF;
-- ----------- --
-- LOOP ARRAY (EACH FIELDS) --
<<label2>>
FOREACH selvalue in ARRAY valrec.MYARRAY
LOOP
IF selvalue IS NULL
THEN selvalue := 'NULL';
ELSE selvalue := quote_literal(selvalue);
END IF;
dumpquery_1 := dumpquery_1 || selvalue || ',';
END LOOP label2;
dumpquery_1 := substring(dumpquery_1 ,1,length(dumpquery_1)-1) || ');';
-- LOOP ARRAY (EACH FIELD) --
-- ----------- --
-- debug: RETURN NEXT dumpquery_0 || dumpquery_1 || ' --' || selquery;
-- debug: RETURN NEXT selquery;
RETURN NEXT dumpquery_0 || dumpquery_1;
END LOOP label1 ;
-- SELECT LOOP --
-- ----------- --
RETURN ;
END
$BODY$
LANGUAGE plpgsql VOLATILE;
And then :
-- for a range
SELECT dump('public', 'my_table','my_id between 123456 and 123459');
-- for the entire table
SELECT dump('public', 'my_table','true');
tested on my postgres 9.1, with a table with mixed field datatype (text, double, int,timestamp without time zone, etc).
That's why the CAST in TEXT type is needed.
My test run correctly for about 9M lines, looks like it fail just before 18 minutes of running.
ps : I found an equivalent for mysql on the WEB.
You can make view of the table with specifit records and then dump sql file
CREATE VIEW foo AS
SELECT id,name,city FROM nyummy.cimory WHERE city = 'tokyo'
I just knocked up a quick procedure to do this. It only works for a single row, so I create a temporary view that just selects the row I want, and then replace the pg_temp.temp_view with the actual table that I want to insert into.
CREATE OR REPLACE FUNCTION dv_util.gen_insert_statement(IN p_schema text, IN p_table text)
RETURNS text AS
$BODY$
DECLARE
selquery text;
valquery text;
selvalue text;
colvalue text;
colrec record;
BEGIN
selquery := 'INSERT INTO ' || quote_ident(p_schema) || '.' || quote_ident(p_table);
selquery := selquery || '(';
valquery := ' VALUES (';
FOR colrec IN SELECT table_schema, table_name, column_name, data_type
FROM information_schema.columns
WHERE table_name = p_table and table_schema = p_schema
ORDER BY ordinal_position
LOOP
selquery := selquery || quote_ident(colrec.column_name) || ',';
selvalue :=
'SELECT CASE WHEN ' || quote_ident(colrec.column_name) || ' IS NULL' ||
' THEN ''NULL''' ||
' ELSE '''' || quote_literal('|| quote_ident(colrec.column_name) || ')::text || ''''' ||
' END' ||
' FROM '||quote_ident(p_schema)||'.'||quote_ident(p_table);
EXECUTE selvalue INTO colvalue;
valquery := valquery || colvalue || ',';
END LOOP;
-- Replace the last , with a )
selquery := substring(selquery,1,length(selquery)-1) || ')';
valquery := substring(valquery,1,length(valquery)-1) || ')';
selquery := selquery || valquery;
RETURN selquery;
END
$BODY$
LANGUAGE plpgsql VOLATILE;
Invoked thus:
SELECT distinct dv_util.gen_insert_statement('pg_temp_' || sess_id::text,'my_data')
from pg_stat_activity
where procpid = pg_backend_pid()
I haven't tested this against injection attacks, please let me know if the quote_literal call isn't sufficient for that.
Also it only works for columns that can be simply cast to ::text and back again.
Also this is for Greenplum but I can't think of a reason why it wouldn't work on Postgres, CMIIW.
I was in need of a way where I can generate insert statements without creating a temp table (in production). I did see some useful arguments to the the pg_dump above but still ended up devising for a way to
generate the insert statements and dump into a file
The below statement did the trick which I feel will be useful for people who end up here for similar answer.
$ /usr/local/bin/pg_dump -h the_db_host_address -d the_db_name --table=schema_name.table_name --data-only --column-inserts -U postgres -p the_port_number -v -f /Users/the_user/folder_name/insrt_stmts_file_name.sql
The next thing is a prompt which asks the password, in the case above I provided the postgres password but any other user should work fine which has the read capability.
I ran the just the insert statements from the file named:
insrt_stmts_file_name.sql in DBeaver client.
But the same can be run from the command prompt as well using the following script:
/usr/local/bin/psql -h the_db_host_address -d the_db_name -v -U postgres -f /Users/the_user/folder_name/insrt_stmts_file_name.sql
Reference for pg_dump / psql flags:
-h = host
-d = db name
-v = verbose (it'll output as it progresses)
-U = db user name
-f = file / path
Just to add on a simple way but manual method.
1)Using PGADMIN 4, after querying the data, download the data in csv.
open the csv in any notepad and copy and paste the data in an online csv to sql converter. For example: https://www.convertcsv.com/csv-to-sql.htm.
You can set the name of the target table.The output is sql insert scripts.
Copy the INSERT scripts back into PGADMIN4 in the targeted db query window.
have u tried in pgadmin executing query with " EXECUTE QUERY WRITE RESULT TO FILE " option
its only export the data, else try like
pg_dump -t view_name DB_name > db.sql
-t option used for ==> Dump only tables (or views or sequences) matching table, refer
Related
Oracle - BULK COLLECT INTO VARRAY used with Bind Variables only collecting column headers
Quick Disclaimer: First thing out of the way, I know the preferred way of handling dynamic SQL in Oracle now is the DBMS_SQL package but unfortunately my application team does not have the grants to execute these procs at the moment and I am hoping to get this quick workaround knocked out before our DBA team gets back to me. Also, this database is on Oracle 12c. Script Goal: I recently developed a Stored Proc (let's call it Original) that uses values in a "control table" to make a large number of updates to certain columns in a database with many schemas and tables. This script I am struggling with now (let's call it Test) is meant to be a quick loop through those columns affected by Original so as to verify that everything worked expectedly. Ultimately, I want to output the top 5 results of each changed column and hand a spooled file to my testing team for validation. The control_table used in both scripts has 4 columns and looks like this: OWNER TABLE_NAME COLUMN_NAME ALGORITHM Schema1 TableA ColumnA Method1 Schema1 TableB ColumnB Method1 Schema2 TableC ColumnC Method2 An example of one of the tables that gets updated by Original (let's say for TableA above) would be: OtherCol1 OtherCol2 ColumnA OtherCol3 Ignored Ignored UpdatedData1 Ignored Ignored Ignored UpdatedData2 Ignored Ignored Ignored UpdatedData3 Ignored Issue with Test script: I have the dynamic SQL - I believe - working as it needs and I have been trying to figure out how best to print the results of the EXECUTE IMMEDIATE command to output. In doing some reading, I found that BULK COLLECT INTO should allow me to store the results of the dynamic queries into a COLLECTION which I can then print with dbms_output. I have attempted to do this with both a TABLE and a VARRAY but in both cases when I print, I am finding that the data stored in my collection is the column header of my dynamic query instead of the query values! The only thing I can think that could be the problem is the combining of BULK COLLECT INTO with the USING command when I run the dynamic statement but I have seen nothing in the documentation to indicate that these two commands are incompatible and my Test procedure below compiles without issue (and even seems to run ok). Test Script: SET SERVEROUTPUT ON SIZE UNLIMITED; DECLARE l_script VARCHAR2(500); l_errm VARCHAR2(64); TYPE results IS VARRAY(5) OF VARCHAR2(250); va_cols results; --Defining here with a VARRAY but I have also tried with a table BEGIN FOR c_col IN( SELECT owner, table_name, column_name, algorithm FROM control_list) LOOP l_errm := NULL; va_cols := NULL; BEGIN dbms_output.put_line('Column '|| c_col.column_name || ' of table ' || c_col.owner || '.' || c_col.table_name || ' used algorithm ' || c_col.algorithm); l_script := 'SELECT :1 FROM ' || c_col.owner || '.' || c_col.table_name || ' WHERE :2 IS NOT NULL FETCH FIRST 5 ROWS ONLY'; dbms_output.put_line('Script sent to Exec Immediate: ' || l_script); --Print l_script for debugging EXECUTE IMMEDIATE l_script BULK COLLECT INTO va_cols USING c_col.column_name, c_col.column_name; dbms_output.put_line(va_cols(1)); dbms_output.put_line(va_cols(2)); dbms_output.put_line(va_cols(3)); dbms_output.put_line(va_cols(4)); dbms_output.put_line(va_cols(5)); EXCEPTION WHEN OTHERS THEN l_errm := SUBSTR(SQLERRM, 1, 64); dbms_output.put_line(' ERROR: ' || l_errm || '. Skipping row'); CONTINUE; END; END LOOP; END; / So my intended dbms_output of the script above is: Column ColumnA of table Schema1.TableA used algorithm Method1 Script sent to Exec Immediate: SELECT :1 FROM SCHEMA1.TABLEA WHERE :2 IS NOT NULL FETCH FIRST 5 ROWS ONLY UpdatedData1 UpdatedData2 UpdatedData3 UpdatedData4 UpdatedData5 Instead, however, bizarrely, what I am getting when I run this is: Column ColumnA of table Schema1.TableA used algorithm Method1 Script sent to Exec Immediate: SELECT :1 FROM SCHEMA1.TABLEA WHERE :2 IS NOT NULL FETCH FIRST 5 ROWS ONLY ColumnA ColumnA ColumnA ColumnA ColumnA Has anyone seen this before and know what I am doing wrong? Thanks in advance!!
You can't use bind variables to change what columns you're referencing. You use bind variables to specify particular values at runtime. When you do l_script := 'SELECT :1 FROM ' || c_col.owner || '.' || c_col.table_name || ' WHERE :2 IS NOT NULL FETCH FIRST 5 ROWS ONLY'; EXECUTE IMMEDIATE l_script BULK COLLECT INTO va_cols USING c_col.column_name, c_col.column_name; you're telling Oracle that you want to select the literal string in the variable c_col.column_name. Not the column in the table by that name. Which is why every row returns that literal value. You'd need to dynamically assemble the SQL statement with the column names, not try to use them as bind variables. So something like l_script := 'SELECT ' || c_col.column_name || ' FROM ' || c_col.owner || '.' || c_col.table_name || ' WHERE ' || c_col.column_name || ' IS NOT NULL FETCH FIRST 5 ROWS ONLY'; EXECUTE IMMEDIATE l_script BULK COLLECT INTO va_cols;
This is approximately what you want. I outer cursor over tables and column to inspect that generate the dynamic SQL. Inner loop reading the column values from the previous query DECLARE TYPE CurTyp IS REF CURSOR; v_cursor CurTyp; v_value VARCHAR2(200); v_stmt_str VARCHAR2(200); BEGIN FOR c IN ( SELECT table_name, column_name FROM control_list) LOOP dbms_output.put_line('tab: '||c.table_name); v_stmt_str := 'SELECT '||c.column_name||' FROM '|| c.table_name; OPEN v_cursor FOR v_stmt_str; LOOP FETCH v_cursor INTO v_value; EXIT WHEN v_cursor%NOTFOUND; dbms_output.put_line('col: '||c.column_name||' val: '||v_value); END LOOP; END LOOP; CLOSE v_cursor; END; /
PostgreSQL PK sequence and Auto incrment problem after moving exisitng MS SQL DB to Postgres [duplicate]
I ran into the problem that my primary key sequence is not in sync with my table rows. That is, when I insert a new row I get a duplicate key error because the sequence implied in the serial datatype returns a number that already exists. It seems to be caused by import/restores not maintaining the sequence properly.
-- 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; Source - Ruby Forum
pg_get_serial_sequence can be used to avoid any incorrect assumptions about the sequence name. This resets the sequence in one shot: SELECT pg_catalog.setval(pg_get_serial_sequence('table_name', 'id'), (SELECT MAX(id) FROM table_name)+1); Or more concisely: SELECT pg_catalog.setval(pg_get_serial_sequence('table_name', 'id'), MAX(id)) FROM table_name; However this form can't handle empty tables correctly, since max(id) is null, and neither can you setval 0 because it would be out of range of the sequence. One workaround for this is to resort to the ALTER SEQUENCE syntax i.e. ALTER SEQUENCE table_name_id_seq RESTART WITH 1; ALTER SEQUENCE table_name_id_seq RESTART; -- 8.4 or higher But ALTER SEQUENCE is of limited use because the sequence name and restart value cannot be expressions. It seems the best all-purpose solution is to call setval with false as the 3rd parameter, allowing us to specify the "next value to use": SELECT setval(pg_get_serial_sequence('t1', 'id'), coalesce(max(id),0) + 1, false) FROM t1; This ticks all my boxes: avoids hard-coding the actual sequence name handles empty tables correctly handles tables with existing data, and does not leave a hole in the sequence Finally, note that pg_get_serial_sequence only works if the sequence is owned by the column. This will be the case if the incrementing column was defined as a serial type, however if the sequence was added manually it is necessary to ensure ALTER SEQUENCE .. OWNED BY is also performed. i.e. if serial type was used for table creation, this should all work: CREATE TABLE t1 ( id serial, name varchar(20) ); SELECT pg_get_serial_sequence('t1', 'id'); -- returns 't1_id_seq' -- reset the sequence, regardless whether table has rows or not: SELECT setval(pg_get_serial_sequence('t1', 'id'), coalesce(max(id),0) + 1, false) FROM t1; But if sequences were added manually: CREATE TABLE t2 ( id integer NOT NULL, name varchar(20) ); CREATE SEQUENCE t2_custom_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1; ALTER TABLE t2 ALTER COLUMN id SET DEFAULT nextval('t2_custom_id_seq'::regclass); ALTER SEQUENCE t2_custom_id_seq OWNED BY t2.id; -- required for pg_get_serial_sequence SELECT pg_get_serial_sequence('t2', 'id'); -- returns 't2_custom_id_seq' -- reset the sequence, regardless whether table has rows or not: SELECT setval(pg_get_serial_sequence('t2', 'id'), coalesce(max(id),0) + 1, false) FROM t1;
The shortest and fastest way SELECT setval('tbl_tbl_id_seq', max(tbl_id)) FROM tbl; tbl_id being the serial or IDENTITY column of table tbl, drawing from the sequence tbl_tbl_id_seq (resulting default name). See: Auto increment table column If you don't know the name of the attached sequence (which doesn't have to be in default form), use pg_get_serial_sequence() (works for IDENTITY, too): SELECT setval(pg_get_serial_sequence('tbl', 'tbl_id'), max(tbl_id)) FROM tbl; There is no off-by-one error here. The manual: The two-parameter form sets the sequence's last_value field to the specified value and sets its is_called field to true, meaning that the next nextval will advance the sequence before returning a value. Bold emphasis mine. If the table can be empty, and to actually start from 1 in this case: SELECT setval(pg_get_serial_sequence('tbl', 'tbl_id') , COALESCE(max(tbl_id) + 1, 1) , false) FROM tbl; We can't just use the 2-parameter form and start with 0 because the lower bound of sequences is 1 by default (unless customized). Safe under concurrent write load To also defend against concurrent sequence activity or writes, lock the table in SHARE mode. It keeps concurrent transactions from writing a higher number (or anything at all). To also take clients into account that may have fetched sequence numbers in advance without any locks on the main table, yet (can happen in certain setups), only increase the current value of the sequence, never decrease it. That may seem paranoid, but that's in accord with the nature of sequences and defending against concurrency issues. BEGIN; LOCK TABLE tbl IN SHARE MODE; SELECT setval('tbl_tbl_id_seq', max(tbl_id)) FROM tbl HAVING max(tbl_id) > (SELECT last_value FROM tbl_tbl_id_seq); -- prevent lower number COMMIT; SHARE mode is strong enough for the purpose. The manual: This mode protects a table against concurrent data changes. It conflicts with ROW EXCLUSIVE mode. The commands UPDATE, DELETE, and INSERT acquire this lock mode on the target table.
This will reset all sequences from public making no assumptions about table or column names. Tested on version 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%';
ALTER SEQUENCE sequence_name RESTART WITH (SELECT max(id) FROM table_name); Doesn't work. Copied from #tardate answer: SELECT setval(pg_get_serial_sequence('table_name', 'id'), MAX(id)) FROM table_name;
In the example below, the table name is users and the schema name is public (default schema), replace it according to your needs. 1. Check the max id: SELECT MAX(id) FROM public.users; 2. Check the next value: SELECT nextval('public."users_id_seq"'); 3. If the next value is lower than the max id, reset it: SELECT setval('public."users_id_seq"', (SELECT MAX(id) FROM public.users) ); Note: nextval() will increment the sequence before returning the current value while currval() would just return the current value, as documented here.
This command for only change auto generated key sequence value in postgresql ALTER SEQUENCE "your_sequence_name" RESTART WITH 0; In place of zero you can put any number from which you want to restart sequence. default sequence name will "TableName_FieldName_seq". For example, if your table name is "MyTable" and your field name is "MyID", then your sequence name will be "MyTable_MyID_seq". This is answer is same as #murugesanponappan's answer, but there is a syntax error in his solution. you can not use sub query (select max()...) in alter command. So that either you have to use fixed numeric value or you need to use a variable in place of sub query.
Reset all sequences, no assumptions about names except that the primary key of each table is "id": CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text, columnname text) RETURNS "pg_catalog"."void" AS $body$ DECLARE BEGIN EXECUTE 'SELECT setval( pg_get_serial_sequence(''' || tablename || ''', ''' || columnname || '''), (SELECT COALESCE(MAX(id)+1,1) FROM ' || tablename || '), false)'; END; $body$ LANGUAGE 'plpgsql'; select table_name || '_' || column_name || '_seq', reset_sequence(table_name, column_name) from information_schema.columns where column_default like 'nextval%';
These functions are fraught with perils when sequence names, column names, table names or schema names have funny characters such as spaces, punctuation marks, and the like. I have written this: CREATE OR REPLACE FUNCTION sequence_max_value(oid) RETURNS bigint VOLATILE STRICT LANGUAGE plpgsql AS $$ DECLARE tabrelid oid; colname name; r record; newmax bigint; BEGIN FOR tabrelid, colname IN SELECT attrelid, attname FROM pg_attribute WHERE (attrelid, attnum) IN ( SELECT adrelid::regclass,adnum FROM pg_attrdef WHERE oid IN (SELECT objid FROM pg_depend WHERE refobjid = $1 AND classid = 'pg_attrdef'::regclass ) ) LOOP FOR r IN EXECUTE 'SELECT max(' || quote_ident(colname) || ') FROM ' || tabrelid::regclass LOOP IF newmax IS NULL OR r.max > newmax THEN newmax := r.max; END IF; END LOOP; END LOOP; RETURN newmax; END; $$ ; You can call it for a single sequence by passing it the OID and it will return the highest number used by any table that has the sequence as default; or you can run it with a query like this, to reset all the sequences in your database: select relname, setval(oid, sequence_max_value(oid)) from pg_class where relkind = 'S'; Using a different qual you can reset only the sequence in a certain schema, and so on. For example, if you want to adjust sequences in the "public" schema: select relname, setval(pg_class.oid, sequence_max_value(pg_class.oid)) from pg_class, pg_namespace where pg_class.relnamespace = pg_namespace.oid and nspname = 'public' and relkind = 'S'; Note that due to how setval() works, you don't need to add 1 to the result. As a closing note, I have to warn that some databases seem to have defaults linking to sequences in ways that do not let the system catalogs have full information of them. This happens when you see things like this in psql's \d: alvherre=# \d baz Tabla «public.baz» Columna | Tipo | Modificadores ---------+---------+------------------------------------------------ a | integer | default nextval(('foo_a_seq'::text)::regclass) Note that the nextval() call in that default clause has a ::text cast in addition to the ::regclass cast. I think this is due to databases being pg_dump'ed from old PostgreSQL versions. What will happen is that the function sequence_max_value() above will ignore such a table. To fix the problem, you can redefine the DEFAULT clause to refer to the sequence directly without the cast: alvherre=# alter table baz alter a set default nextval('foo_a_seq'); ALTER TABLE Then psql displays it properly: alvherre=# \d baz Tabla «public.baz» Columna | Tipo | Modificadores ---------+---------+---------------------------------------- a | integer | default nextval('foo_a_seq'::regclass) As soon as you've fixed that, the function works correctly for this table as well as all others that might use the same sequence.
I suggest this solution found on postgres wiki. It updates all sequences of your tables. SELECT 'SELECT SETVAL(' || quote_literal(quote_ident(PGT.schemaname) || '.' || quote_ident(S.relname)) || ', COALESCE(MAX(' ||quote_ident(C.attname)|| '), 1) ) FROM ' || quote_ident(PGT.schemaname)|| '.'||quote_ident(T.relname)|| ';' FROM pg_class AS S, pg_depend AS D, pg_class AS T, pg_attribute AS C, pg_tables AS PGT WHERE S.relkind = 'S' AND S.oid = D.objid AND D.refobjid = T.oid AND D.refobjid = C.attrelid AND D.refobjsubid = C.attnum AND T.relname = PGT.tablename ORDER BY S.relname; How to use(from postgres wiki): Save this to a file, say 'reset.sql' Run the file and save its output in a way that doesn't include the usual headers, then run that output. Example: Example: psql -Atq -f reset.sql -o temp psql -f temp rm temp Original article(also with fix for sequence ownership) here
Yet another plpgsql - resets only if max(att) > then lastval do --check seq not in sync $$ declare _r record; _i bigint; _m bigint; begin for _r in ( SELECT relname,nspname,d.refobjid::regclass, a.attname, refobjid FROM pg_depend d JOIN pg_attribute a ON a.attrelid = d.refobjid AND a.attnum = d.refobjsubid JOIN pg_class r on r.oid = objid JOIN pg_namespace n on n.oid = relnamespace WHERE d.refobjsubid > 0 and relkind = 'S' ) loop execute format('select last_value from %I.%I',_r.nspname,_r.relname) into _i; execute format('select max(%I) from %s',_r.attname,_r.refobjid) into _m; if coalesce(_m,0) > _i then raise info '%',concat('changed: ',_r.nspname,'.',_r.relname,' from:',_i,' to:',_m); execute format('alter sequence %I.%I restart with %s',_r.nspname,_r.relname,_m+1); end if; end loop; end; $$ ; also commenting the line --execute format('alter sequence will give the list, not actually resetting the value
Reset all sequence from public CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text) RETURNS "pg_catalog"."void" AS $body$ DECLARE BEGIN EXECUTE 'SELECT setval( ''' || tablename || '_id_seq'', ' || '(SELECT id + 1 FROM "' || tablename || '" ORDER BY id DESC LIMIT 1), false)'; END; $body$ LANGUAGE 'plpgsql'; select sequence_name, reset_sequence(split_part(sequence_name, '_id_seq',1)) from information_schema.sequences where sequence_schema='public';
This issue happens with me when using entity framework to create the database and then seed the database with initial data, this makes the sequence mismatch. I Solved it by Creating a script to run after seeding the database: DO $do$ DECLARE tablename text; BEGIN -- change the where statments to include or exclude whatever tables you need FOR tablename IN SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND table_type='BASE TABLE' AND table_name != '__EFMigrationsHistory' LOOP EXECUTE format('SELECT setval(pg_get_serial_sequence(''"%s"'', ''Id''), (SELECT MAX("Id") + 1 from "%s"))', tablename, tablename); END LOOP; END $do$
Some really hardcore answers here, I'm assuming it used to be really bad at around the time when this has been asked, since a lot of answers from here don't works for version 9.3. The documentation since version 8.0 provides an answer to this very question: SELECT setval('serial', max(id)) FROM distributors; Also, if you need to take care of case-sensitive sequence names, that's how you do it: SELECT setval('"Serial"', max(id)) FROM distributors;
My version use the first one, with some error checking... BEGIN; CREATE OR REPLACE FUNCTION reset_sequence(_table_schema text, _tablename text, _columnname text, _sequence_name text) RETURNS pg_catalog.void AS $BODY$ DECLARE BEGIN PERFORM 1 FROM information_schema.sequences WHERE sequence_schema = _table_schema AND sequence_name = _sequence_name; IF FOUND THEN EXECUTE 'SELECT setval( ''' || _table_schema || '.' || _sequence_name || ''', ' || '(SELECT MAX(' || _columnname || ') FROM ' || _table_schema || '.' || _tablename || ')' || '+1)'; ELSE RAISE WARNING 'SEQUENCE NOT UPDATED ON %.%', _tablename, _columnname; END IF; END; $BODY$ LANGUAGE 'plpgsql'; SELECT reset_sequence(table_schema, table_name, column_name, table_name || '_' || column_name || '_seq') FROM information_schema.columns WHERE column_default LIKE 'nextval%'; DROP FUNCTION reset_sequence(_table_schema text, _tablename text, _columnname text, _sequence_name text) ; COMMIT;
Putting it all together CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text) RETURNS "pg_catalog"."void" AS $body$ DECLARE BEGIN EXECUTE 'SELECT setval( pg_get_serial_sequence(''' || tablename || ''', ''id''), (SELECT COALESCE(MAX(id)+1,1) FROM ' || tablename || '), false)'; END; $body$ LANGUAGE 'plpgsql'; will fix 'id' sequence of the given table (as usually necessary with django for instance).
Recheck all sequence in public schema function CREATE OR REPLACE FUNCTION public.recheck_sequence ( ) RETURNS void AS $body$ DECLARE _table_name VARCHAR; _column_name VARCHAR; _sequence_name VARCHAR; BEGIN FOR _table_name IN SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = 'public' LOOP FOR _column_name IN SELECT column_name FROM information_schema.columns WHERE table_name = _table_name LOOP SELECT pg_get_serial_sequence(_table_name, _column_name) INTO _sequence_name; IF _sequence_name IS NOT NULL THEN EXECUTE 'SELECT setval('''||_sequence_name||''', COALESCE((SELECT MAX('||quote_ident(_column_name)||')+1 FROM '||quote_ident(_table_name)||'), 1), FALSE);'; END IF; END LOOP; END LOOP; END; $body$ LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER COST 100;
before I had not tried yet the code : in the following I post the version for the sql-code for both Klaus and user457226 solutions which worked on my pc [Postgres 8.3], with just some little adjustements for the Klaus one and of my version for the user457226 one. Klaus solution : drop function IF EXISTS rebuilt_sequences() RESTRICT; CREATE OR REPLACE FUNCTION rebuilt_sequences() RETURNS integer as $body$ DECLARE sequencedefs RECORD; c integer ; BEGIN FOR sequencedefs IN Select constraint_column_usage.table_name as tablename, constraint_column_usage.table_name as tablename, constraint_column_usage.column_name as columnname, replace(replace(columns.column_default,'''::regclass)',''),'nextval(''','') as sequencename from information_schema.constraint_column_usage, information_schema.columns where constraint_column_usage.table_schema ='public' AND columns.table_schema = 'public' AND columns.table_name=constraint_column_usage.table_name AND constraint_column_usage.column_name = columns.column_name AND columns.column_default is not null LOOP EXECUTE 'select max('||sequencedefs.columnname||') from ' || sequencedefs.tablename INTO c; IF c is null THEN c = 0; END IF; IF c is not null THEN c = c+ 1; END IF; EXECUTE 'alter sequence ' || sequencedefs.sequencename ||' restart with ' || c; END LOOP; RETURN 1; END; $body$ LANGUAGE plpgsql; select rebuilt_sequences(); user457226 solution : --drop function IF EXISTS reset_sequence (text,text) RESTRICT; CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text,columnname text) RETURNS bigint --"pg_catalog"."void" AS $body$ DECLARE seqname character varying; c integer; BEGIN select tablename || '_' || columnname || '_seq' into seqname; EXECUTE 'SELECT max("' || columnname || '") FROM "' || tablename || '"' into c; if c is null then c = 0; end if; c = c+1; --because of substitution of setval with "alter sequence" --EXECUTE 'SELECT setval( "' || seqname || '", ' || cast(c as character varying) || ', false)'; DOES NOT WORK!!! EXECUTE 'alter sequence ' || seqname ||' restart with ' || cast(c as character varying); RETURN nextval(seqname)-1; END; $body$ LANGUAGE 'plpgsql'; select sequence_name, PG_CLASS.relname, PG_ATTRIBUTE.attname, reset_sequence(PG_CLASS.relname,PG_ATTRIBUTE.attname) from PG_CLASS join PG_ATTRIBUTE on PG_ATTRIBUTE.attrelid = PG_CLASS.oid join information_schema.sequences on information_schema.sequences.sequence_name = PG_CLASS.relname || '_' || PG_ATTRIBUTE.attname || '_seq' where sequence_schema='public';
This answer is a copy from mauro. drop function IF EXISTS rebuilt_sequences() RESTRICT; CREATE OR REPLACE FUNCTION rebuilt_sequences() RETURNS integer as $body$ DECLARE sequencedefs RECORD; c integer ; BEGIN FOR sequencedefs IN Select DISTINCT(constraint_column_usage.table_name) as tablename, constraint_column_usage.column_name as columnname, replace(replace(columns.column_default,'''::regclass)',''),'nextval(''','') as sequencename from information_schema.constraint_column_usage, information_schema.columns where constraint_column_usage.table_schema ='public' AND columns.table_schema = 'public' AND columns.table_name=constraint_column_usage.table_name AND constraint_column_usage.column_name = columns.column_name AND columns.column_default is not null ORDER BY sequencename LOOP EXECUTE 'select max('||sequencedefs.columnname||') from ' || sequencedefs.tablename INTO c; IF c is null THEN c = 0; END IF; IF c is not null THEN c = c+ 1; END IF; EXECUTE 'alter sequence ' || sequencedefs.sequencename ||' minvalue '||c ||' start ' || c ||' restart with ' || c; END LOOP; RETURN 1; END; $body$ LANGUAGE plpgsql; select rebuilt_sequences();
If you see this error when you are loading custom SQL data for initialization, another way to avoid this is: Instead of writing: INSERT INTO book (id, name, price) VALUES (1 , 'Alchemist' , 10), Remove the id (primary key) from initial data INSERT INTO book (name, price) VALUES ('Alchemist' , 10), This keeps the Postgres sequence in sync !
To restart all sequence to 1 use: -- Create Function CREATE OR REPLACE FUNCTION "sy_restart_seq_to_1" ( relname TEXT ) RETURNS "pg_catalog"."void" AS $BODY$ DECLARE BEGIN EXECUTE 'ALTER SEQUENCE '||relname||' RESTART WITH 1;'; END; $BODY$ LANGUAGE 'plpgsql'; -- Use Function SELECT relname ,sy_restart_seq_to_1(relname) FROM pg_class WHERE relkind = 'S';
The Klaus answer is the most useful, execpt for a little miss : you have to add DISTINCT in select statement. However, if you are sure that no table+column names can be equivalent for two different tables, you can also use : select sequence_name, --PG_CLASS.relname, PG_ATTRIBUTE.attname reset_sequence(split_part(sequence_name, '_id_seq',1)) from PG_CLASS join PG_ATTRIBUTE on PG_ATTRIBUTE.attrelid = PG_CLASS.oid join information_schema.sequences on information_schema.sequences.sequence_name = PG_CLASS.relname || '_' || PG_ATTRIBUTE.attname where sequence_schema='public'; which is an extension of user457226 solution for the case when some interested column name is not 'ID'.
I spent an hour trying to get djsnowsill's answer to work with a database using Mixed Case tables and columns, then finally stumbled upon the solution thanks to a comment from Manuel Darveau, but I thought I could make it a bit clearer for everyone: CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text, columnname text) RETURNS "pg_catalog"."void" AS $body$ DECLARE BEGIN EXECUTE format('SELECT setval(pg_get_serial_sequence(''%1$I'', %2$L), (SELECT COALESCE(MAX(%2$I)+1,1) FROM %1$I), false)',tablename,columnname); END; $body$ LANGUAGE 'plpgsql'; SELECT format('%s_%s_seq',table_name,column_name), reset_sequence(table_name,column_name) FROM information_schema.columns WHERE column_default like 'nextval%'; This has the benefit of: not assuming ID column is spelled a particular way. not assuming all tables have a sequence. working for Mixed Case table/column names. using format to be more concise. To explain, the problem was that pg_get_serial_sequence takes strings to work out what you're referring to, so if you do: "TableName" --it thinks it's a table or column 'TableName' --it thinks it's a string, but makes it lower case '"TableName"' --it works! This is achieved using ''%1$I'' in the format string, '' makes an apostrophe 1$ means first arg, and I means in quotes
select 'SELECT SETVAL(' || seq [ 1] || ', COALESCE(MAX('||column_name||')+1, 1) ) FROM '||table_name||';' from ( SELECT table_name, column_name, column_default, regexp_match(column_default, '''.*''') as seq from information_schema.columns where column_default ilike 'nextval%' ) as sequense_query
Just run below command: SELECT setval('my_table_seq', (SELECT max(id) FROM my_table));
Ugly hack to fix it using some shell magic, not a great solution but might inspire others with similar problems :) pg_dump -s <DATABASE> | grep 'CREATE TABLE' | awk '{print "SELECT setval(#" $3 "_id_seq#, (SELECT MAX(id) FROM " $3 "));"}' | sed "s/#/'/g" | psql <DATABASE> -f -
A method to update all sequences in your schema that are used as an ID: DO $$ DECLARE r RECORD; BEGIN FOR r IN (SELECT tablename, pg_get_serial_sequence(tablename, 'id') as sequencename FROM pg_catalog.pg_tables WHERE schemaname='YOUR_SCHEMA' AND tablename IN (SELECT table_name FROM information_schema.columns WHERE table_name=tablename and column_name='id') order by tablename) LOOP EXECUTE 'SELECT setval(''' || r.sequencename || ''', COALESCE(MAX(id), 1), MAX(id) IS NOT null) FROM ' || r.tablename || ';'; END LOOP; END $$;
So I can tell there aren't enough opinions or reinvented wheels in this thread, so I decided to spice things up. Below is a procedure that: is focused (only affects) on sequences that are associated with tables works for both SERIAL and GENERATED AS IDENTITY columns works for good_column_names and "BAD_column_123" names automatically assigns the respective sequences' defined start value if the table is empty allows for a specific sequences to be affected only (in schema.table.column notation) has a preview mode 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 ; to preview: call pg_reset_all_table_sequences(); to commit: call pg_reset_all_table_sequences(true); to specify only your target table: call pg_reset_all_table_sequences('schema.table.column');
Try reindex. UPDATE: As pointed out in the comments, this was in reply to the original question.
There are a lot of good answers here. I had the same need after reloading my Django database. But I needed: All in one Function Could fix one or more schemas at a time Could fix all or just one table at a time Also wanted a nice way to see exactly what had changed, or not changed This seems very similar need to what the original ask was for. Thanks to Baldiry and Mauro got me on the right track. drop function IF EXISTS reset_sequences(text[], text) RESTRICT; CREATE OR REPLACE FUNCTION reset_sequences( in_schema_name_list text[] = '{"django", "dbaas", "metrics", "monitor", "runner", "db_counts"}', in_table_name text = '%') RETURNS text[] as $body$ DECLARE changed_seqs text[]; DECLARE sequence_defs RECORD; c integer ; BEGIN FOR sequence_defs IN select DISTINCT(ccu.table_name) as table_name, ccu.column_name as column_name, replace(replace(c.column_default,'''::regclass)',''),'nextval(''','') as sequence_name from information_schema.constraint_column_usage ccu, information_schema.columns c where ccu.table_schema = ANY(in_schema_name_list) and ccu.table_schema = c.table_schema AND c.table_name = ccu.table_name and c.table_name like in_table_name AND ccu.column_name = c.column_name AND c.column_default is not null ORDER BY sequence_name LOOP EXECUTE 'select max(' || sequence_defs.column_name || ') from ' || sequence_defs.table_name INTO c; IF c is null THEN c = 1; else c = c + 1; END IF; EXECUTE 'alter sequence ' || sequence_defs.sequence_name || ' restart with ' || c; changed_seqs = array_append(changed_seqs, 'alter sequence ' || sequence_defs.sequence_name || ' restart with ' || c); END LOOP; changed_seqs = array_append(changed_seqs, 'Done'); RETURN changed_seqs; END $body$ LANGUAGE plpgsql; Then to Execute and See the changes run: select * from unnest(reset_sequences('{"django", "dbaas", "metrics", "monitor", "runner", "db_counts"}')); Returns activity_id_seq restart at 22 api_connection_info_id_seq restart at 4 api_user_id_seq restart at 1 application_contact_id_seq restart at 20
ERROR at line 1: ORA-00911: invalid character ORA-06512: at line 17
I am not a frequent user of database & once in a while i need to create/run/execute a few PL/SQL blocks. I have a similar situation right now, where I have the below block which while executing as SYS as SYSDBA in oracle database user throws the error :- DECLARE * ERROR at line 1: ORA-00911: invalid character ORA-06512: at line 17 The PL/SQL Block is as below :- DECLARE TYPE RefCurTyp IS REF CURSOR; alter_tbl VARCHAR2(200); a_null CHAR(1); tbl VARCHAR2(200); clmn VARCHAR2(200); dtyp VARCHAR2(200) ; dlth VARCHAR2(200); c RefCurTyp; BEGIN open c for 'select utc.table_name, utc.column_name, utc.data_type, utc.data_length FROM user_tab_columns utc, user_tables ut WHERE utc.data_type = ''VARCHAR2'' AND utc.char_used =''B'' AND ut.table_name = utc.table_name'; LOOP dbms_output.put_line(clmn); FETCH c INTO tbl, clmn, dtyp, dlth; EXIT WHEN c%NOTFOUND; EXECUTE IMMEDIATE 'alter table '||tbl||' modify ('||clmn||' '||dtyp||'('||dlth||' CHAR))'; END LOOP; CLOSE c; END; Even after pounding my head on it for 3 days i am unable to figure out the issue with this. Any input is appreciated. While executing the same code via TOAD i get :-
You can use dbms_output to display the dynamic statement you are executing. To make sure you see and execute the same thing it's simpler to put the statement into a variable (you have one you aren't using). If you change the cursor type you don't need the local variables though, you can construct the statement as part of the cursor query, and then refer to it multiple times; you also won't have to escape your single quotes: set serveroutput on BEGIN FOR r IN ( SELECT 'alter table ' || utc.table_name || ' modify (' || utc.column_name || ' ' || utc.data_type || '(' || utc.data_length || ' CHAR))' as alter_stmt FROM user_tab_columns utc JOIN user_tables ut ON ut.table_name = utc.table_name WHERE utc.data_type = 'VARCHAR2' AND utc.char_used ='B' ) LOOP dbms_output.put_line(r.alter_stmt); execute immediate r.alter_stmt; END LOOP; END; / I suspect you have a table or column name that contains an invalid character and was created with a quoted identifier. That will probably be obvious from the output you see immediately before it fails. You can easily add double quotes to all of the identifiers by concatenating them as part of the statement generation: BEGIN FOR r IN ( SELECT 'alter table "' || utc.table_name || '" modify ("' || utc.column_name || '" ' || utc.data_type || '(' || utc.data_length || ' CHAR))' as alter_stmt FROM user_tab_columns utc JOIN user_tables ut ON ut.table_name = utc.table_name WHERE utc.data_type = 'VARCHAR2' AND utc.char_used ='B' ) LOOP dbms_output.put_line(r.alter_stmt); execute immediate r.alter_stmt; END LOOP; END; / You said you're running this while connected as SYS, and you're looking at user_tables, so you are altering tables owned by SYS - which seems like a very bad idea. Even if you don't intend to modify built-in data dictionary tables, this will do so, and that would imply you've been creating your own objects in the SYS schema - which is generally considered a very bad idea. You should create a separate user account and only create and modify objects in that schema. In my 11g instance SYS has a table that generates output from my first query as: alter table _default_auditing_options_ modify (A VARCHAR2(1 CHAR)); ... which would get ORA-00911 because of the underscores. If the identifiers are quoted then it would work: alter table "_default_auditing_options_" modify ("A" VARCHAR2(1 CHAR)); ... but, once again, you should not be altering built-in tables.
Duplicate postgresql schema including sequences
My database layout needs to create new schema for each new customer. Currently I use internal function I found on the net and modified a little bit. CREATE FUNCTION copy_schema( source_schema character varying, target_schema character varying, copy_data boolean) RETURNS integer AS $BODY$ DECLARE t_ex integer := 0; s_ex integer := 0; src_table character varying; trg_table character varying; BEGIN if (select 1 from pg_namespace where nspname = source_schema) THEN -- we have defined target schema s_ex := 1; END IF; IF (s_ex = 0) THEN -- no source schema exist RETURN 0; END IF; if (select 1 from pg_namespace where nspname = target_schema) THEN -- we have defined target schema need to sync all table layout t_ex := 1; ELSE EXECUTE 'CREATE SCHEMA '||target_schema||' AUTHORIZATION user'; END IF; FOR src_table IN SELECT table_name FROM information_schema.TABLES WHERE table_schema = source_schema LOOP trg_table := target_schema||'.'||src_table; EXECUTE 'CREATE TABLE ' || trg_table || ' (LIKE ' || source_schema || '.' || src_table || ' INCLUDING ALL)'; IF (copy_data = true) THEN EXECUTE 'INSERT INTO ' || trg_table || '(SELECT * FROM ' || source_schema || '.' || src_table || ')'; END IF; END LOOP; return t_ex; END; $BODY$ LANGUAGE plpgsql VOLATILE COST 100; The problem with this script is that tables in new schema continue to use source schema's sequences. Is there way using sql statements (or other reliable way) to get fresh copy of sequences (or even another reliable way to duplicate entire schema) for the newly created tables?
The root of the problem The connection to the old sequence comes from a plain default value for the involved column. I quote the manual here: Default expressions for the copied column definitions will only be copied if INCLUDING DEFAULTS is specified. The default behavior is to exclude default expressions, resulting in the copied columns in the new table having null default. Since you create new tables with INCLUDING ALL And: INCLUDING ALL is an abbreviated form of INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING STORAGE INCLUDING COMMENTS. .. you get the same default. You can either exclude defaults or explicitly change default values including nextval() for the new tables after you created them. I don't think there is any middle ground. Simpler with dump / hack the dump / restore or even another reliable way to duplicate entire schema You could dump the schema of schema (same word, different meaning) with pg_dump: pg_dump $DB -p $PORT -n $SCHEMA -sf /var/lib/postgresql/your_name.pgsql Hack the dump (meaning: use a text editor on it, or script it): exchange the schema name at the top of the dump, and all other occurrences in SET search_path and as schema-qualification for sequences and possibly more. If you chose a unique name for the schema, a single run of global search & replace with your favorite tool (sed or vim or ...) should do the job. Then run the SQL script with psql against the same or any other database: psql $DB -p $PORT -f /var/lib/postgresql/your_name.pgsql > /dev/null Contrary to what I first posted, serial columns are still split up in the dump (at least in PostgreSQL 9.1.5). The SQL script creates sequences separately, attaches them to the serial column with: ALTER SEQUENCE seq OWNED BY tbl.col; and sets the default value separately. As an aside: Current versions of pgAdmin reverse engineer serial columns in DDL scripts when all the requirements are met.
And so after some thinking I went along with updating sql function mentioned in my first post so now it looks like this: CREATE FUNCTION copy_schema( source_schema character varying, target_schema character varying, copy_data boolean) RETURNS integer AS $BODY$ DECLARE t_ex integer := 0; s_ex integer := 0; src_table character varying; trg_table character varying; BEGIN if (select 1 from pg_namespace where nspname = source_schema) THEN -- we have defined target schema s_ex := 1; END IF; IF (s_ex = 0) THEN -- no source schema exist RETURN 0; END IF; if (select 1 from pg_namespace where nspname = target_schema) THEN -- we have defined target schema need to sync all table layout t_ex := 1; ELSE EXECUTE 'CREATE SCHEMA '||target_schema||' AUTHORIZATION user'; END IF; FOR src_table IN SELECT table_name FROM information_schema.TABLES WHERE table_schema = source_schema LOOP trg_table := target_schema||'.'||src_table; EXECUTE 'CREATE TABLE ' || trg_table || ' (LIKE ' || source_schema || '.' || src_table || ' INCLUDING ALL)'; EXECUTE 'CREATE SEQUENCE ' || trg_table || '_id_seq OWNED BY '||trg_table || '.id'; EXECUTE 'ALTER TABLE ' || trg_table || ' ALTER COLUMN id SET DEFAULT nextval('''|| trg_table || '_id_seq''::regclass)'; IF (copy_data = true) THEN EXECUTE 'INSERT INTO ' || trg_table || '(SELECT * FROM ' || source_schema || '.' || src_table || ')'; END IF; END LOOP; return t_ex; END; $BODY$ LANGUAGE plpgsql VOLATILE COST 100; This is not quite universal solution for everybody, but as all my tables in schema have serial field named id, it fits me. Version suggested by #erwin-brandstetter with dump / hack dump file / restore dump file back again is commonly seen on the forums as the way to go. In case of dedicated server it could work, in case of shared hosting (or need of less dependencies on outside scripts) the way of internal function seems better.
You could simply backup up the schema, then rename it in the DB, then restore the file that was backed up.
generic stored procedure in oracle
I want to write a PLSQL stored procedure that accepts a table name as argument. This table is source table. Now inside my procedure i want to manipulate the fields of that table. EX: I want to insert the records of this source table into another target table whose name is XYZ_<source table name>. The column names for source and target tables are the same. But there may be some extra fields in target table. How do i do it? The order of column names is not same.
You will have to build the INSERT statement dynamically. create or replace procedure gen_insert (p_src_table in user_tables.table_name%type , p_no_of_rows out pls_integer) is col_str varchar2(16000); begin for rec in ( select column_name , column_id from user_tab_columns where table_name = p_src_table order by column_id ) loop if rec.column_id != 1 then col_str := col_str || ',' || rec.column_name; else col_str := rec.column_name; end if: end loop; execute immediate 'insert into xyz_' || p_src_table || '(' || col_str || ')' || ' select ' || col_str || ' from ' || p_src_table; p_no_of_rows := sql%rowcount; end; / Obviously you may want to include some error handling and other improvements. edit Having edited your question I see you have a special requirement for naming the target table which was obscured by the SO formatting.
You can do this using Dynamic SQL. Here's a link with basic info on Oracle Dynamic SQL