#python #postgresql #psycopg2 #execute
#python #postgresql #psycopg2 #выполнить
Вопрос:
Я пытаюсь вставить список строк / кортежей в мою базу данных postgresql. Итак, я нашел функцию execute_values() … Но это не работает, чтобы строки автоматически получали идентификатор.
Мой код:
query = "INSERT INTO " self.table " VALUES %s"
execute_values(self.cursor,query, row)
self.con.commit()
Первый столбец в моей базе данных — это идентификатор, а первый столбец моего кортежа строк — ТЕКСТ (второй столбец в базе данных также является ТЕКСТОМ)
Итак, я получаю сообщение об ошибке:
psycopg2.errors.InvalidTextRepresentation: invalid input syntax for type integer: "blub"
LINE 1: INSERT INTO whales VALUES ('blub...
Так что я думаю, это из-за идентификатора.
Также я пробовал template
, но результат не лучше:
database.py", line 204, in insert_row
execute_values(self.cursor,query, row, "(%(name)s,%(is_member)s)")
File "C:JustaPathenvlibsite-packagespsycopg2extras.py", line 1289, in execute_values
parts.append(cur.mogrify(template, args))
TypeError: tuple indices must be integers or slices, not str
Возможно, я неправильно прочитал документацию или не понимаю шаблоны…
Теперь вопрос: как я могу с этим справиться? При «обычных» исполнениях мне не нужно добавлять идентификатор. Есть ли способ сделать это с помощью execute_values()? Или это единственный способ сначала получить идентификаторы с помощью select и также присвоить неиспользуемые идентификаторы execute_values?
Комментарии:
1. Вы должны указать столбцы, к которым принадлежат данные:
INSERT INTO foo (text_col_1, text_col_2) VALUES ...
, предполагаяid
, что столбец автоматически увеличивается.
Ответ №1:
В Postgresql для допустимого SQL список значений в INSERT
инструкции должен соответствовать указанному списку имен столбцов. Если список имен столбцов не указан, то указанный список N
значений должен соответствовать первым N
столбцам в таблице с возможностью указания DEFAULT
для вставки значения по умолчанию для этих столбцов. В отношении столбца Postgresql SERIAL
, такого как тот, который объявлен в следующей таблице примера:
CREATE TABLE test_insert_with_serial_column (
id SERIAL PRIMARY KEY,
col1 VARCHAR,
col2 VARCHAR
);
Допустимы следующие инструкции SQL:
-- Specifying only the col1 and col2 columns, SERIAL id column will "auto-increment"
INSERT INTO test_insert_with_serial_column(col1, col2) VALUES ('one_text', 'other_text');
-- Specifying values for all columns with DEFAULT for the SERIAL id column
INSERT INTO test_insert_with_serial_column VALUES (DEFAULT, 'one_text', 'other_text');
Однако следующий SQL недопустим:
-- Failed to specify an integer value for the first SERIAL id column
INSERT INTO test_insert_with_serial_column VALUES ('one_text', 'other_text');
Это связано с тем, что one_text
будет связано со SERIAL
id
столбцом и, следовательно,
с сообщением об ошибке, аналогичным тому, которое видно по результатам операции.
psycopg2.extras.execute_values
это вспомогательная функция, которую можно использовать для более эффективной вставки нескольких строк значений (т.Е. Списка списка значений). Входной SQL-запрос должен содержать один %s
заполнитель, который будет заменен template
заполнителями of . Значение по умолчанию template
(т.Е. Если None
Указано) представляет собой простую позиционную последовательность заполнителей (т.Е. (%s, %s, ...)
) с количеством заполнителей, равным количеству значений, которые нужно вставить для каждой строки. Поэтому вызов execute_values
с:
execute_values(cur, "INSERT INTO test_insert_with_serial_column VALUES %s",
[('one_text', 'other_text')])
приводит к тому же недопустимому SQL, что и выше. Обратите внимание, что приведенное выше использование execute_values
для вставки только
одной строки вместо нескольких строк не имеет значения для ошибки.
Существует несколько решений этой проблемы:
- Укажите имена столбцов, соответствующие значениям во входном запросе
execute_values(cur, "INSERT INTO test_insert_with_serial_column (col1, col2) VALUES %s",
[('one_text', 'other_text')])
- Укажите a
template
, который указывает aDEFAULT
дляid
столбца
execute_values(cur, "INSERT INTO test_insert_with_serial_column VALUES %s",
[('one_text', 'other_text')], template="(DEFAULT, %s, %s)")
- Объявите
SERIAL
столбец как последний столбец в таблице
CREATE TABLE test_insert_with_serial_column (
col1 VARCHAR,
col2 VARCHAR,
id SERIAL PRIMARY KEY
);
Затем, вызывая:
execute_values(cur, "INSERT INTO test_insert_with_serial_column VALUES %s",
[('one_text', 'other_text')])
работает. Это последнее решение немного нетрадиционно, но оно использует тот факт, что если список
столбцов не указан, то указанный список N
значений должен соответствовать первым
N
столбцам в таблице.
Комментарии:
1. Проблема, которая мешает мне использовать первые два решения, заключается в том, что столбцы могут быть переменной величиной. Мой подготовленный оператор insert предназначен для использования для нескольких таблиц с различным количеством столбцов. Единственный способ, которым я могу избежать этой проблемы, — использовать ваше третье решение.