Сделать дубликат строки в Postgresql

avatar
Ankit
8 апреля 2018 в 08:52
3634
2
0

Я пишу сценарий миграции для переноса базы данных. Мне нужно продублировать строку, увеличив первичный ключ, учитывая, что в другой базе данных может быть 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

Вот, хорошо, что мне не нужно упоминать все имена столбцов. Я могу выбрать все столбцы, указав *. Но в то же время я также получаю повторяющуюся ошибку ключа.

Каково решение этой проблемы? Любая помощь будет оценена по достоинству. Заранее спасибо.

Источник
mmuzahid
8 апреля 2018 в 08:56
0

Явно определите имя столбца. например INSERT INTO table_name SELECT col2, col3, .... coln FROM table_name WHERE id=255;

404
8 апреля 2018 в 10:05
1

Знаете ли вы заранее, какие столбцы не должны дублироваться, например. столбец (столбцы) PK, или вы его вообще не знаете (или у них может быть любое имя)? Другими словами, были бы вы довольны жестко запрограммированными именами столбцов PK или предоставлением их в качестве входных данных для функции, или у вас не было бы этой информации?

Ankit
8 апреля 2018 в 12:59
0

@eurotrash Да, я был бы рад вести колонки ПК. Это просто "id". Какой запрос для этого?

404
8 апреля 2018 в 13:01
0

Также этот столбец получает значение по умолчанию (так что вы можете просто исключить этот столбец из вставки, и он будет иметь действительный идентификатор) или вам нужно указать значение самостоятельно?

Ankit
8 апреля 2018 в 13:03
0

@eurotrash Это установлено как автоматическое увеличение. Если я не укажу значение при вставке записи, оно автоматически подберет следующее значение.

Kaushik Nayak
11 апреля 2018 в 08:04
0

@Ankit: Вы пробовали решение, которое я вам дал. Проголосуйте или, по крайней мере, дайте отзыв, работает это или нет.

Ankit
11 апреля 2018 в 08:13
0

@KaushikNayak На самом деле нет. Сделаю в течении 10 дней.

Ответы (2)

avatar
Kaushik Nayak
8 апреля 2018 в 10:09
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;
Ankit
15 апреля 2018 в 07:33
0

Спасибо Кошик. Я только что сделал несколько изменений в сценарии в соответствии с моим требованием, и он работает нормально. Я использовал 2-й вариант.

avatar
404
8 апреля 2018 в 13:17
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. Вы можете поместить этот код в функцию и использовать его для любой таблицы, которую захотите, или просто использовать его вот так и отредактировать его для любой таблицы.

Ankit
11 апреля 2018 в 08:14
0

Tnx. Скоро проверю.