我正在使用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)
但首先,这对于我需要的东西是否过度,其次,我怎样才能将其中一个作为简单的字符串执行?
这里一个非常常见的问题是如何进行upsert,这是MySQL调用的INSERT ... ON DUPLICATE UPDATE,标准支持作为MERGE操作的一部分.
鉴于PostgreSQL不直接支持它(在第9.5页之前),你是如何做到这一点的?考虑以下:
CREATE TABLE testtable (
id integer PRIMARY KEY,
somedata text NOT NULL
);
INSERT INTO testtable (id, somedata) VALUES
(1, 'fred'),
(2, 'bob');
Run Code Online (Sandbox Code Playgroud)
现在,假设你想"UPSERT"的元组(2, 'Joe'),(3, 'Alan'),因此新表的内容是:
(1, 'fred'),
(2, 'Joe'), -- Changed value of existing tuple
(3, 'Alan') -- Added new tuple
Run Code Online (Sandbox Code Playgroud)
这是人们在讨论时所谈论的内容upsert.至关重要的是,任何方法在同一个表上存在多个事务时都必须是安全的 - 通过使用显式锁定,或以其他方式抵御由此产生的竞争条件.
关于PostgreSQL中的重复更新,在Insert上广泛讨论了这个主题?,但这是关于MySQL语法的替代品,随着时间的推移,它已经成长为一些无关的细节.我正在研究明确的答案.
这些技术对于"插入如果不存在,否则什么都不做"也很有用,即"插入...复制键忽略".
我有两个postgresql表:
table name column names
----------- ------------------------
login_log ip | etc.
ip_location ip | location | hostname | etc.
Run Code Online (Sandbox Code Playgroud)
我想得到每个login_log没有行的IP地址ip_location.
我尝试了这个查询,但它抛出了语法错误.
SELECT login_log.ip
FROM login_log
WHERE NOT EXIST (SELECT ip_location.ip
FROM ip_location
WHERE login_log.ip = ip_location.ip)
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)ERROR: syntax error at or near "SELECT" LINE 3: WHERE NOT EXIST (SELECT ip_location.ip`
我也想知道这个查询(通过调整使其工作)是否是用于此目的的最佳性能查询.
我在PostgreSQL 9.5中有以下UPSERT:
INSERT INTO chats ("user", "contact", "name")
VALUES ($1, $2, $3),
($2, $1, NULL)
ON CONFLICT("user", "contact") DO NOTHING
RETURNING id;
Run Code Online (Sandbox Code Playgroud)
如果没有冲突,则返回如下内容:
----------
| id |
----------
1 | 50 |
----------
2 | 51 |
----------
Run Code Online (Sandbox Code Playgroud)
但如果存在冲突,则不会返回任何行:
----------
| id |
----------
Run Code Online (Sandbox Code Playgroud)
id如果没有冲突,我想返回新列,或者返回id冲突列的现有列.
可以这样做吗?如果是这样,怎么样?
我正在执行以下代码,但是,偶尔会发生重复键冲突,整个插入将停止。如何忽略此类错误并让查询执行有效条目?
代码:
query_data = ','.join(cur.mogrify('(%s,%s)', row) for row in data)
insert_q = "INSERT INTO <table> VALUES {0};".format(query_data)
try:
cur.execute(insert_q)
except psycopg2.Error:
self.logger.exception('Database error')
con.commit()
Run Code Online (Sandbox Code Playgroud)
更新2:
我在下面发布了我自己的答案,解决了问题。它使用 Postgres 中新的 ON CONFLICT 语法。
更新1:
在 except 块内提交存在一个问题,但是,我发现,如果不这样做,所有其他插入都不会执行,并出现以下错误:
ERROR: current transaction is aborted, commands ignored until end of transaction block
Run Code Online (Sandbox Code Playgroud)
为了避免混淆,在 try except 之后添加了提交
我试图使用该EXCEPT子句从表中检索数据.我希望获得table1除了存在的所有行之外的所有行table2.据我所知,以下内容不起作用:
CREATE TABLE table1(pk_id int, fk_id_tbl2 int);
CREATE TABLE table2(pk_id int);
Select fk_id_tbl2
FROM table1
Except
Select pk_id
FROM table2
Run Code Online (Sandbox Code Playgroud)
我可以使用的唯一方法EXCEPT似乎是从相同的表中选择或从不同的表中选择具有相同列名的列.
有人可以解释一下如何最好地使用explain子句吗?
postgresql ×6
sql ×3
python ×2
upsert ×2
bulkinsert ×1
except ×1
exists ×1
left-join ×1
null ×1
psycopg2 ×1
sql-insert ×1
sql-merge ×1