Вы можете быть довольно близко ...
Предложение RETURNING
будет работать со вставками с несколькими значениями, например:
insert into some_table (col1, col2) values
(val1, val2), (val3, val4),
(val5, val6), (val7, val8)
returning id
Предполагая, что some_table
имеет serial
, вы получите 4 результата от этого
заявление. Также будет работать с insert into ... select
:
insert into some_table (col1, col2)
select col1, col2
from some_other_source returning id
Но в обоих случаях, если вы укажете on conflict do nothing
, весь оператор потерпит неудачу в случае конфликта, поэтому одна плохая запись убивает транзакцию.
Но учтите, что returning
также работает с удалениями:
delete from some_table where col1 = 'bob' returning id
Соединение с предложением от @JacobH: массовая загрузка в темп
таблица, отфильтруйте конфликтующие строки, затем вставьте оставшиеся, не конфликтующие
строк. Вы упомянули copy
, так что я предполагаю, что уже есть .csv, что примерно
соответствует месту назначения. Примерно так:
with conn.cursor() as stmt:
#create a constraint-free temp table based on your destination table
#the `where 0 = 1` ensures it's empty
stmt.execute('select * into temp tmp_some_table from some_table where 0 = 1')
#bulk load into the temp table:
with open('some.csv') as infile:
stmt.copy_from(infile, 'tmp_some_table', sep=',', columns=['col1', 'col2'])
#strip out your conflicts. note that we are returning col1 (assumed to be a unique key)
#you can do as many passes as needed...
stmt.execute('delete from tmp_some_table tst using some_table st where tst.col1 = st.col1 returning col1')
dupe_keys = stmt.fetchall() #all your deleted, conflicting keys
#bulk insert non-conflicting values
stmt.execute('insert into some_table (col1, col2) select (col1, col2) from tmp_some_table returning id')
inserted_ids = stmt.fetchall() #all the ids created from the insert
Бонус в том, что это должно быть очень быстро по сравнению с повторением и вызовом execute
-
по сути, вы делаете все в 4 заявлениях; основная часть сети ввода / вывода
находится на том первоначальном импорте CSV против N циклов на N вставках записей.
Все остальное происходит в базе данных. Временная таблица, вероятно, останется в
памяти, если она достаточно мала.
Поймите, я опоздал на этот ответ, но я надеюсь, что это поможет.