postgresql: как получить первичные ключи строк, вставленных с помощью массовой копии?

Цель такова: у меня есть набор значений для таблицы A и набор значений для таблицы B. Значения, входящие в B, ссылаются на значения в A (через внешний ключ), поэтому после вставки значений A мне нужно знать, как ссылаться на них при вставке значений B. Мне нужно, чтобы это было как можно быстрее.

Я сделал вставку значений B с массовой копией из:

def bulk_insert_copyfrom(cursor, table_name, field_names, values):
    if not values: return

    print "bulk copy from prepare..."
    str_vals = "\n".join("\t".join(adapt(val).getquoted() for val in cur_vals) for cur_vals in values)
    strf = StringIO(str_vals)
    print "bulk copy from execute..."
    cursor.copy_from(strf, table_name, columns=tuple(field_names))

Это было намного быстрее, чем выполнение запроса INSERT VALUES ... RETURNING id. Я хотел бы сделать то же самое для значений A, но мне нужно знать id вставленных строк.

Есть ли способ выполнить массовое копирование таким образом, но получить поле id (первичный ключ) вставленных строк, чтобы я знал, какой id связан с каким value?

Если нет, то какой лучший способ достичь моей цели?

РЕДАКТИРОВАТЬ: Пример данных по запросу:

a_val1 = [1, 2, 3]
a_val2 = [4, 5, 6]
a_vals = [a_val1, a_val2]

b_val1 = [a_val2, 5, 6, 7]
b_val2 = [a_val1, 100, 200, 300]
b_val3 = [a_val2, 9, 14, 6]
b_vals = [b_val1, b_val2, b_val3]

Я хочу вставить a_vals, затем вставить b_vals, используя внешние ключи вместо ссылок на объекты списка.


person Claudiu    schedule 03.11.2011    source источник


Ответы (2)


Сгенерируйте идентификаторы самостоятельно.

  1. НАЧАТЬ транзакцию
  2. Стол блокировки а
  3. вызовите nextval() - это ваш первый идентификатор
  4. сгенерируйте свою КОПИЮ с идентификаторами на месте
  5. то же самое для таблицы б
  6. вызовите setval() с вашим окончательным идентификатором + 1
  7. СОВЕРШИТЬ транзакцию

На шаге 2 вы, вероятно, также захотите заблокировать отношение последовательности. Если код вызывает nextval() и прячет этот идентификатор где-то, он может быть уже использован к тому времени, когда он его использует.

Немного не по теме: есть параметр «кеш», который вы можете установить, если у вас много бэкэндов, выполняющих много вставок. Это увеличивает счетчик в блоках.

http://www.postgresql.org/docs/9.1/static/sql-createsequence.html

person Richard Huxton    schedule 04.11.2011
comment
Я закончил тем, что сделал что-то похожее на это. У меня было два поля идентификатора: batch_id и inside_batch_id. batch_id, который я получил с помощью nextval, within_batch_id, который я только что сгенерировал сам. затем я сделал выбор с помощью batch_id, чтобы получить то, что я только что вставил, и выровнял их с внутри_batch_id. Благодарность! - person Claudiu; 04.11.2011

На самом деле вы можете сделать это по-другому, что вам нужно:

  • Начать транзакцию
  • Создайте временную таблицу с такой же (или почти такой же) схемой
  • COPY данных в эту временную таблицу
  • Выполняйте обычные INSERT INTO .. FROM temp_table ... RETURNING id, other_columns
  • Совершить

взято из здесь (в С#, но алгоритм тот же)

person Tony    schedule 11.10.2017