0

I am writing migration script to migrate database. I have to duplicate the row by incrementing primary key considering that different database can have n number of different columns in the table. I can't write each and every column in query. If i simply just copy the row then, I am getting duplicate key error.

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

Here, It's good that I don't have to mention all column names. I can select all columns by giving *. But, same time I am also getting duplicate key error.

What's the solution of this problem? Any help would be appreciated. Thanks in advance.

7
  • Define column name explicitly. e.g. INSERT INTO table_name SELECT col2, col3, .... coln FROM table_name WHERE id=255; Commented Apr 8, 2018 at 8:56
  • 1
    Do you know ahead of time which columns should not be duplicated e.g. the PK column(s), or do you not know it at all (or they could have any name)? In other words, would you be happy with hard coding those PK column names or supplying them as input to a function, or would you not have that information? Commented Apr 8, 2018 at 10:05
  • @eurotrash Yes, I would be happy to write PK columns. It is just "id". Whats the query for this? Commented Apr 8, 2018 at 12:59
  • Also does that column get a default value (so you could just exclude that column from the insert and it will have a valid id) or do you have to provide a value yourself? Commented Apr 8, 2018 at 13:01
  • @eurotrash It is set as auto increment. If i dont supply the value while inserting record then it pich the next value automatically. Commented Apr 8, 2018 at 13:03

2 Answers 2

2

If you are willing to type all column names, you may write

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;

Other option (without typing all columns , but you know the primary key ) is to CREATE a temp table, update it and re-insert within a transaction.

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;
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Kaushik. I just made few changes in script as per my requirement and it is working fine. I used 2nd option.
1

This is just a DO block but you could create a function that takes things like the table name etc as parameters.

Setup:

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');

Code to duplicate values without the primary key column:

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 $$

The query it creates and runs is: INSERT INTO public.t1 (a,b,c,e,f) SELECT a,b,c,e,f FROM public.t1. It's selected all the columns apart from the PK one. You could put this code in a function and use it for any table you wanted, or just use it like this and edit it for whatever table.

1 Comment

Tnx. Will check it out soon.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.