Postgres удалить перед вставкой в ​​одну транзакцию - PullRequest
1 голос
/ 22 января 2020

PostgreSQL DB: v 9.4.24

create table my_a_b_data ... // with a_uuid, b_uuid, and c columns

ПРИМЕЧАНИЕ: my_a_b_data хранит ссылки на таблицы a и b. Таким образом, он хранит uuids a и b.

, где: primary key (a_uuid, b_uuid)

есть также index :

create unique index my_a_b_data_pkey
    on my_a_b_data (a_uuid, b_uuid);

In Java jdb c -подобный код в области действия одной транзакции: (start() -> [code (delete, insert)] ->commit()]) (org.postgresql:postgresql:42.2.5 driver)

delete from my_a_b_data where b_uuid = 'bbb';
insert into my_a_b_data (a_uuid, b_uuid, c) values ('aaa', 'bbb', null);

Я обнаружил, что вставка не удалась, потому что удаление еще не удалено. Таким образом, он терпит неудачу, потому что его нельзя дублировать.

Q: Является ли какое-то ограничение в PostgreSQL тем, что DB не может выполнить удаление и вставить в одну транзакцию, потому что PostgreSQL не обновляет свои индексы до тех пор, пока не будет выполнена фиксация удаления, поэтому вставка не удастся, поскольку идентификатор или ключ (что бы мы ни использовали) уже существует в индексе?

Какое было бы возможное решение? Разделение на две транзакции?

ОБНОВЛЕНИЕ: порядок точно такой же. Когда я тестирую sql в консоли SQL. Работает нормально. Мы используем библиотеку JDBI v 5.29.

там это выглядит так:

 @Transaction
 @SqlUpdate("insert into my_a_b_data (...; // similar for the delete
 public abstract void addB() ..

Итак, в коде:

this.begin();
this.deleteByB(b_id);
this.addB(a_id, b_id);
this.commit();

1 Ответ

0 голосов
/ 22 января 2020

У меня была похожая проблема с вставкой дублированных значений, и я решил ее, используя вместо этого «Вставить и обновить». Я создал этот процесс на Python, но вы можете воспроизвести его:

  1. Сначала вы создаете временную таблицу, например таблицу назначения, в которую хотите вставить значения, разница в том, что что эта таблица удаляется после коммита.

    CREATE TEMP TABLE temp_my_a_b_data 
    (LIKE public.my_a_b_data INCLUDING DEFAULTS) 
    ON COMMIT DROP;
    
  2. Я создал CSV (мне пришлось объединить разные данные для ввода) со значениями, которые я хочу ввести / вставить в свой table и я использовали функцию COPY , чтобы вставить их в temp_table ( temp_my_a_b_data ).

    Я нашел этот код в этом посте, связанный с Java и COPY PostgreSQL - \ копировать команду :

    String query ="COPY tmp from 'E://load.csv' delimiter ','";
    
  3. Использовать INSERT INTO, но с предложением ON_CONFLICT , которое Вы можете решить выполнить действие, когда вставка не может быть выполнена из-за указанных ограничений, в приведенном ниже случае мы делаем обновление:

    INSERT INTO public.my_a_b_data 
    SELECT * 
    FROM temp_my_a_b_data 
    ON CONFLICT (a_uuid, b_uuid,c) DO UPDATE 
      SET a_uuid = EXCLUDED.a_uuid, 
          b_uuid = EXCLUDED. c = EXCLUDED.c;`
    

Соображения:

Я не уверен, но вы могли бы выполнить третий шаг, не используя предыдущие шаги, временная таблица или копия из. Вы можете просто задать значения oop:

INSERT INTO public.my_a_b_data VALUES(value1, value2, null) 
ON CONFLICT (a_uuid, b_uuid,c) DO UPDATE 
   SET a_uuid = EXCLUDED.a_uuid, 
       b_uuid = EXCLUDED.b_uuid, c = EXCLUDED.c;
...