AP2*_*257 304 python postgresql sql-insert
我正在使用Python写入postgres数据库:
sql_string = "INSERT INTO hundred (name,name_slug,status) VALUES ("
sql_string += hundred + ", '" + hundred_slug + "', " + status + ");"
cursor.execute(sql_string)
Run Code Online (Sandbox Code Playgroud)
但由于我的一些行是相同的,我收到以下错误:
psycopg2.IntegrityError: duplicate key value
violates unique constraint "hundred_pkey"
Run Code Online (Sandbox Code Playgroud)
如何编写'INSERT除非此行已存在'SQL语句?
我见过这样的复杂陈述:
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
Run Code Online (Sandbox Code Playgroud)
但首先,这对于我需要的东西是否过度,其次,我怎样才能将其中一个作为简单的字符串执行?
Ari*_*rie 401
Postgres 9.5(自2016-01-07发布)提供了一个"upsert"命令,也称为INSERT的ON CONFLICT子句:
INSERT ... ON CONFLICT DO NOTHING/UPDATE
Run Code Online (Sandbox Code Playgroud)
它解决了使用并发操作时可能遇到的许多微妙问题,其他一些答案提出了这些问题.
Joh*_*Doe 357
如何编写'INSERT除非此行已存在'SQL语句?
有一种在PostgreSQL中进行条件INSERT的好方法:
INSERT INTO example_table
(id, name)
SELECT 1, 'John'
WHERE
NOT EXISTS (
SELECT id FROM example_table WHERE id = 1
);
Run Code Online (Sandbox Code Playgroud)
CAVEAT但是,对于并发写操作,这种方法并非100%可靠.SELECT在NOT EXISTS反半连接和INSERT自身之间存在非常微小的竞争条件.在这种情况下它可能会失败.
Kub*_*aun 47
一种方法是创建一个非约束(无唯一索引)表,将所有数据插入并执行与此不同的选择,以插入到您的百表中.
如此高水平.我假设在我的示例中所有三列都是不同的,因此对于step3,将NOT EXITS连接更改为仅连接到百表中的唯一列.
创建临时表.请参阅此处的文档.
CREATE TEMPORARY TABLE temp_data(name, name_slug, status);
Run Code Online (Sandbox Code Playgroud)将数据插入临时表.
INSERT INTO temp_data(name, name_slug, status);
Run Code Online (Sandbox Code Playgroud)将任何索引添加到临时表.
主表插入.
INSERT INTO hundred(name, name_slug, status)
SELECT DISTINCT name, name_slug, status
FROM hundred
WHERE NOT EXISTS (
SELECT 'X'
FROM temp_data
WHERE
temp_data.name = hundred.name
AND temp_data.name_slug = hundred.name_slug
AND temp_data.status = status
);
Run Code Online (Sandbox Code Playgroud)Qua*_*noi 16
不幸的是,PostgreSQL既不支持MERGE也不支持ON DUPLICATE KEY UPDATE,所以你必须在两个语句中做到这一点:
UPDATE invoices
SET billed = 'TRUE'
WHERE invoices = '12345'
INSERT
INTO invoices (invoiceid, billed)
SELECT '12345', 'TRUE'
WHERE '12345' NOT IN
(
SELECT invoiceid
FROM invoices
)
Run Code Online (Sandbox Code Playgroud)
你可以把它包装成一个函数:
CREATE OR REPLACE FUNCTION fn_upd_invoices(id VARCHAR(32), billed VARCHAR(32))
RETURNS VOID
AS
$$
UPDATE invoices
SET billed = $2
WHERE invoices = $1;
INSERT
INTO invoices (invoiceid, billed)
SELECT $1, $2
WHERE $1 NOT IN
(
SELECT invoiceid
FROM invoices
);
$$
LANGUAGE 'sql';
Run Code Online (Sandbox Code Playgroud)
然后打电话给它:
SELECT fn_upd_invoices('12345', 'TRUE')
Run Code Online (Sandbox Code Playgroud)
tua*_*ptn 13
这正是我面临的问题,我的版本是 9.5
我用下面的 SQL 查询解决了它。
INSERT INTO example_table (id, name)
SELECT 1 AS id, 'John' AS name FROM example_table
WHERE NOT EXISTS(
SELECT id FROM example_table WHERE id = 1
)
LIMIT 1;
Run Code Online (Sandbox Code Playgroud)
希望对版本>= 9.5 有相同问题的人有所帮助。
谢谢阅读。
cri*_*stm 11
你可以使用VALUES - Postgres中提供的:
INSERT INTO person (name)
SELECT name FROM person
UNION
VALUES ('Bob')
EXCEPT
SELECT name FROM person;
Run Code Online (Sandbox Code Playgroud)
小智 8
我们可以使用 upsert 来简化查询
insert into invoices (invoiceid, billed)
values ('12345', 'TRUE')
on conflict (invoiceid) do
update set billed=EXCLUDED.billed;
Run Code Online (Sandbox Code Playgroud)
我知道这个问题是从不久前开始的,但我认为这可能对某人有所帮助.我认为最简单的方法是通过触发器.例如:
Create Function ignore_dups() Returns Trigger
As $$
Begin
If Exists (
Select
*
From
hundred h
Where
-- Assuming all three fields are primary key
h.name = NEW.name
And h.hundred_slug = NEW.hundred_slug
And h.status = NEW.status
) Then
Return NULL;
End If;
Return NEW;
End;
$$ Language plpgsql;
Create Trigger ignore_dups
Before Insert On hundred
For Each Row
Execute Procedure ignore_dups();
Run Code Online (Sandbox Code Playgroud)
从psql提示符执行此代码(或者您希望直接在数据库上执行查询).然后你可以从Python正常插入.例如:
sql = "Insert Into hundreds (name, name_slug, status) Values (%s, %s, %s)"
cursor.execute(sql, (hundred, hundred_slug, status))
Run Code Online (Sandbox Code Playgroud)
请注意,正如@Thomas_Wouters已经提到的,上面的代码利用了参数而不是连接字符串.
有一种使用WITH查询在PostgreSQL中进行条件INSERT的好方法:喜欢:
WITH a as(
select
id
from
schema.table_name
where
column_name = your_identical_column_value
)
INSERT into
schema.table_name
(col_name1, col_name2)
SELECT
(col_name1, col_name2)
WHERE NOT EXISTS (
SELECT
id
FROM
a
)
RETURNING id
Run Code Online (Sandbox Code Playgroud)
插入..不存在是一个好方法。交易条件可以通过交易“信封”来避免:
BEGIN;
LOCK TABLE hundred IN SHARE ROW EXCLUSIVE MODE;
INSERT ... ;
COMMIT;
Run Code Online (Sandbox Code Playgroud)