这里一个非常常见的问题是如何进行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 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
冲突列的现有列.
可以这样做吗?如果是这样,怎么样?
我在表中两列col1
,col2
他们都是独一无二的索引(COL1是唯一的,因此是COL2).
我需要插入到这个表中,使用ON CONFLICT
语法并更新其他列,但我不能同时使用两个列in conflict_target
子句.
有用:
INSERT INTO table
...
ON CONFLICT ( col1 )
DO UPDATE
SET
-- update needed columns here
Run Code Online (Sandbox Code Playgroud)
但是如何为几个列执行此操作,如下所示:
...
ON CONFLICT ( col1, col2 )
DO UPDATE
SET
....
Run Code Online (Sandbox Code Playgroud) 我想通过一个查询将数据插入到3个表中.
我的表如下所示:
CREATE TABLE sample (
id bigserial PRIMARY KEY,
lastname varchar(20),
firstname varchar(20)
);
CREATE TABLE sample1(
user_id bigserial PRIMARY KEY,
sample_id bigint REFERENCES sample,
adddetails varchar(20)
);
CREATE TABLE sample2(
id bigserial PRIMARY KEY,
user_id bigint REFERENCES sample1,
value varchar(10)
);
Run Code Online (Sandbox Code Playgroud)
我将获得一个密钥以换取每次插入,我需要在下一个表中插入该密钥.
我的查询是:
insert into sample(firstname,lastname) values('fai55','shaggk') RETURNING id;
insert into sample1(sample_id, adddetails) values($id,'ss') RETURNING user_id;
insert into sample2(user_id, value) values($id,'ss') RETURNING id;
Run Code Online (Sandbox Code Playgroud)
但是,如果我运行单个查询,他们只是向我返回值,我不能立即在下一个查询中重用它们.
怎么做到这一点?
sql postgresql common-table-expression sql-insert sql-returning
我正在使用PostgreSQL 9.0,我有一个只有一个人工密钥(自动递增序列)和另一个唯一密钥的表.(是的,这个表有一个原因.:))我想通过另一个键查找一个ID,如果它不存在,则插入它:
SELECT id
FROM mytable
WHERE other_key = 'SOMETHING'
Run Code Online (Sandbox Code Playgroud)
然后,如果没有匹配:
INSERT INTO mytable (other_key)
VALUES ('SOMETHING')
RETURNING id
Run Code Online (Sandbox Code Playgroud)
问题:是否可以通过在一个语句中执行这两个操作来保存到DB的往返?如果它不存在,我可以插入行:
INSERT INTO mytable (other_key)
SELECT 'SOMETHING'
WHERE NOT EXISTS (SELECT * FROM mytable WHERE other_key = 'SOMETHING')
RETURNING id
Run Code Online (Sandbox Code Playgroud)
...但是这不会给出现有行的ID.有任何想法吗?如果有帮助,对other_key有一个唯一约束.
在PostgreSQL中,我想创建一个安全包装机制,如果发生异常,它将返回空结果.考虑以下:
SELECT * FROM myschema.mytable;
Run Code Online (Sandbox Code Playgroud)
我可以在客户端应用程序中进行安全包装:
try {
result = execute_query('SELECT value FROM myschema.mytable').fetchall();
}
catch(pg_exception) {
result = []
}
Run Code Online (Sandbox Code Playgroud)
但我可以直接在SQL中做这样的事情吗?我想使下面的代码工作,但似乎它应该被放入DO $$ ... $$
块中,在这里我迷路了.
BEGIN
SELECT * FROM myschema.mytable;
EXCEPTION WHEN others THEN
SELECT unnest(ARRAY[]::TEXT[])
END
Run Code Online (Sandbox Code Playgroud) 如何break
在PostgreSQL中使用该语句?我有这样的结构:
for()
{
for()
{
if(somecondition)
break;
}
}
Run Code Online (Sandbox Code Playgroud)
根据我的理解,它应该只打破内for
循环?
我有一种情况,我经常需要从具有唯一约束的表中获取一行,如果不存在,则创建它并返回.例如我的表可能是:
CREATE TABLE names(
id SERIAL PRIMARY KEY,
name TEXT,
CONSTRAINT names_name_key UNIQUE (name)
);
Run Code Online (Sandbox Code Playgroud)
它包含:
id | name
1 | bob
2 | alice
Run Code Online (Sandbox Code Playgroud)
然后我想:
INSERT INTO names(name) VALUES ('bob')
ON CONFLICT DO NOTHING RETURNING id;
Run Code Online (Sandbox Code Playgroud)
也许:
INSERT INTO names(name) VALUES ('bob')
ON CONFLICT (name) DO NOTHING RETURNING id
Run Code Online (Sandbox Code Playgroud)
让它返回bob的id 1
.但是,RETURNING
只返回插入或更新的行.所以,在上面的例子中,它不会返回任何东西.为了让它按照需要运行,我实际上需要:
INSERT INTO names(name) VALUES ('bob')
ON CONFLICT ON CONSTRAINT names_name_key DO UPDATE
SET name = 'bob'
RETURNING id;
Run Code Online (Sandbox Code Playgroud)
这看起来有点麻烦.我想我的问题是:
不允许(我)期望行为的原因是什么?
有没有更优雅的方式来做到这一点?
我有这个表(由Django生成):
CREATE TABLE feeds_person (
id serial PRIMARY KEY,
created timestamp with time zone NOT NULL,
modified timestamp with time zone NOT NULL,
name character varying(4000) NOT NULL,
url character varying(1000) NOT NULL,
email character varying(254) NOT NULL,
CONSTRAINT feeds_person_name_ad8c7469_uniq UNIQUE (name, url, email)
);
Run Code Online (Sandbox Code Playgroud)
我想批量插入大量使用数据INSERT
与ON CONFLICT
条款.
皱纹是我需要得到所有行的id
背面,无论它们是否已经存在.
在其他情况下,我会做类似的事情:
INSERT INTO feeds_person (created, modified, name, url, email)
VALUES blah blah blah
ON CONFLICT (name, url, email) DO UPDATE SET url = feeds_person.url …
Run Code Online (Sandbox Code Playgroud) 我正在使用python(不是真正相关的)和Postgresql(如果相关的9.2)实现一个简单的基于Web的RSS阅读器.数据库模式如下(基于RSS格式):
CREATE TABLE feed_channel
(
id SERIAL PRIMARY KEY,
name TEXT,
link TEXT NOT NULL,
title TEXT
);
CREATE TABLE feed_content
(
id SERIAL PRIMARY KEY,
channel INTEGER REFERENCES feed_channel(id) ON DELETE CASCADE ON UPDATE CASCADE,
guid TEXT UNIQUE NOT NULL,
title TEXT,
link TEXT,
description TEXT,
pubdate TIMESTAMP
);
Run Code Online (Sandbox Code Playgroud)
当我创建新频道(以及查询更新的Feed信息)时,我请求Feed,将其数据插入feed_channel表,选择新插入的ID - 或现有以避免重复 - 然后将Feed数据添加到feed_content表.典型的情况是:
这是标准的"插入(如果尚未存在,但返回相关ID")问题.为了解决这个问题,我实现了以下存储过程:
CREATE OR REPLACE FUNCTION channel_insert(
p_link feed_channel.link%TYPE,
p_title feed_channel.title%TYPE
) RETURNS feed_channel.id%TYPE AS $$
DECLARE
v_id feed_channel.id%TYPE;
BEGIN
SELECT id …
Run Code Online (Sandbox Code Playgroud) postgresql database-design insert primary-key race-condition
postgresql ×10
sql ×5
upsert ×5
plpgsql ×2
break ×1
django ×1
dynamic-sql ×1
insert ×1
loops ×1
primary-key ×1
sql-insert ×1
sql-merge ×1