Я использую Python для записи в базу данных postgres:
sql_string = "INSERT INTO hundred (name,name_slug,status) VALUES ("
sql_string += hundred + ", '" + hundred_slug + "', " + status + ");"
cursor.execute(sql_string)
Но поскольку некоторые из моих строк идентичны, я получаю следующую ошибку:
psycopg2.IntegrityError: duplicate key value
violates unique constraint "hundred_pkey"
Как я могу написать оператор SQL INSERT, если эта строка уже не существует?
Я видел сложные заявления, как это рекомендуется:
IF EXISTS (SELECT * FROM invoices WHERE invoiceid = '12345')
UPDATE invoices SET billed = 'TRUE' WHERE invoiceid = '12345'
ELSE
INSERT INTO invoices (invoiceid, billed) VALUES ('12345', 'TRUE')
END IF
Но, во-первых, является ли это излишним для того, что мне нужно, а во-вторых, как я могу выполнить один из них в виде простой строки?
postgresql
sql-insert
upsert
AP257
источник
источник
Ответы:
Postgres 9.5 (выпущен с 2016-01-07) предлагает команду «upsert» , также известную как предложение ON CONFLICT для INSERT :
Он решает многие тонкие проблемы, с которыми вы можете столкнуться при использовании параллельной операции, что предлагают некоторые другие ответы.
источник
INSERT INTO distributors (did, dname) VALUES (7, 'Redline GmbH') ON CONFLICT (did) DO NOTHING;
(2) ВСТАВИТЬ, если не существует, иначе ОБНОВЛЕНИЕ -INSERT INTO distributors (did, dname) VALUES (5, 'Gizmo Transglobal'), (6, 'Associated Computing, Inc') ON CONFLICT (did) DO UPDATE SET dname = EXCLUDED.dname;
Эти примеры взяты из руководства - postgresql.org/docs/9.5/static/sql-insert.htmlЕсть хороший способ сделать условную INSERT в PostgreSQL:
CAVEAT Этот подход не является на 100% надежным для одновременных операций записи. Существует очень крошечное состояние гонки между
SELECT
вNOT EXISTS
борьбе с Полусоединением иINSERT
сами. Это может потерпеть неудачу при таких условиях.источник
RETURNS id
например, для полученияid
вставленного или нет?RETURNING id
в и запроса и он вернет либо новый идентификатор строки, либо ничего, если строка не была вставлена.Один из подходов заключается в создании неограниченной (без уникальных индексов) таблицы для вставки всех ваших данных и выбора, отличного от этого, для вставки в сотню таблиц.
Такой высокий уровень был бы. Я предполагаю, что все три столбца различны в моем примере, поэтому для шага 3 измените соединение NOT EXITS, чтобы объединить только уникальные столбцы в таблице сотен.
Создать временную таблицу. Смотрите документы здесь .
Вставить данные во временную таблицу.
Добавьте любые индексы во временную таблицу.
Сделать основной стол вставкой.
источник
SELECT name,name_slug,status
или*
SELECT DISTINCT name, name_slug, status FROM temp_data
?К сожалению, не
PostgreSQL
поддерживает ни то,MERGE
ни другоеON DUPLICATE KEY UPDATE
, поэтому вам придется сделать это в двух утверждениях:Вы можете обернуть это в функцию:
и просто назовите это:
источник
INSERT INTO hundred (name, name_slug, status) SELECT 'Chichester', 'chichester', NULL WHERE 'Chichester' NOT IN (SELECT NAME FROM hundred);
любое количество раз, и он продолжает вставлять строку.CREATE TABLE hundred (name TEXT, name_slug TEXT, status INT); INSERT INTO hundred (name, name_slug, status) SELECT 'Chichester', 'chichester', NULL WHERE 'Chichester' NOT IN (SELECT NAME FROM hundred); INSERT INTO hundred (name, name_slug, status) SELECT 'Chichester', 'chichester', NULL WHERE 'Chichester' NOT IN (SELECT NAME FROM hundred); SELECT * FROM hundred
. Есть одна запись.Вы можете использовать ЦЕННОСТИ - доступные в Postgres:
источник
Я знаю, что этот вопрос давно, но подумал, что это может кому-то помочь. Я думаю, что самый простой способ сделать это через триггер. Например:
Выполните этот код из приглашения psql (или, как вам нравится, для выполнения запросов непосредственно в базе данных). Затем вы можете вставить как обычно из Python. Например:
Обратите внимание, что, как уже упоминалось в @Thomas_Wouters, приведенный выше код использует преимущества параметров, а не объединяет строку.
источник
Есть хороший способ сделать условную INSERT в PostgreSQL с помощью запроса WITH:
источник
Это именно та проблема, с которой я сталкиваюсь, и моя версия 9.5
И я решаю это с помощью SQL-запроса ниже.
Надеюсь, что это поможет кому-то, кто имеет ту же проблему с версией> = 9.5.
Спасибо за чтение.
источник
ВСТАВЬТЕ .. ГДЕ НЕ СУЩЕСТВУЕТ - это хороший подход. А условий гонки можно избежать с помощью «конверта» транзакции:
источник
Это легко с правилами:
Но это не удается при одновременной записи ...
источник
Подход с наибольшим количеством голосов (от Джона Доу) как-то работает для меня, но в моем случае из ожидаемых 422 строк я получаю только 180. Я не мог найти ничего неправильного и вообще не было ошибок, поэтому я искал другое простой подход.
Использование
IF NOT FOUND THEN
послеSELECT
просто отлично работает для меня.(описано в документации PostgreSQL )
Пример из документации:
источник
Класс курсора psycopgs имеет атрибут rowcount .
Таким образом, вы можете сначала попробовать UPDATE и INSERT, только если rowcount равен 0.
Но в зависимости от уровней активности в вашей базе данных вы можете столкнуться с состоянием гонки между UPDATE и INSERT, когда другой процесс может создать эту запись в промежуточный период.
источник
Кажется, что ваш столбец "сто" определен как первичный ключ и поэтому должен быть уникальным, что не так. Проблема не в том, а в ваших данных.
Я предлагаю вам ввести идентификатор в качестве серийного типа для обработки первичного ключа
источник
Если вы скажете, что многие ваши строки идентичны, вы прекратите проверку много раз. Вы можете отправить их, и база данных определит, вставить это или нет с предложением ON CONFLICT следующим образом
источник
Я искал похожее решение, пытаясь найти SQL, который работает как в PostgreSQL, так и в HSQLDB. (Именно HSQLDB сделал это трудным.) Используя ваш пример в качестве основы, этот формат я нашел в другом месте.
источник
Вот общая функция Python, которая, учитывая имя таблицы, столбцы и значения, генерирует эквивалент upsert для postgresql.
импорт JSON
источник
Решение в простом, но не сразу.
Если вы хотите использовать эту инструкцию, вы должны внести одно изменение в базу данных:
после этих изменений «INSERT» будет работать правильно.
источник