相关疑难解决方法(0)

如何在PostgreSQL中UPSERT(MERGE,INSERT ...在DUPLICATE UPDATE上)?

这里一个非常常见的问题是如何进行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 upsert insert-update sql-merge

246
推荐指数
5
解决办法
18万
查看次数

如何在PostgreSQL中使用RETURNING和ON CONFLICT?

我在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冲突列的现有列.
可以这样做吗?如果是这样,怎么样?

sql postgresql upsert sql-returning

127
推荐指数
7
解决办法
4万
查看次数

在ON CONFLICT子句中使用多个conflict_target

我在表中两列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)

postgresql upsert postgresql-9.5

70
推荐指数
4
解决办法
4万
查看次数

使用Postgres一次在3个表中插入数据

我想通过一个查询将数据插入到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

64
推荐指数
4
解决办法
4万
查看次数

在一个命令中选择或插入一行

我正在使用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

32
推荐指数
1
解决办法
1万
查看次数

处理PostgreSQL异常的优雅方式?

在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)

sql postgresql exception-handling dynamic-sql plpgsql

17
推荐指数
1
解决办法
2万
查看次数

PL/pgSQL中的BREAK语句

如何break在PostgreSQL中使用该语句?我有这样的结构:

for()
 {
 for()
 {
  if(somecondition)
  break;
 }
}
Run Code Online (Sandbox Code Playgroud)

根据我的理解,它应该只打破内for循环?

postgresql loops plpgsql break

16
推荐指数
1
解决办法
2万
查看次数

使用ON CONFLICT从INSERT返回行而无需更新

我有一种情况,我经常需要从具有唯一约束的表中获取一行,如果不存在,则创建它并返回.例如我的表可能是:

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)

这看起来有点麻烦.我想我的问题是:

  1. 不允许(我)期望行为的原因是什么?

  2. 有没有更优雅的方式来做到这一点?

sql postgresql upsert postgresql-9.5

16
推荐指数
1
解决办法
3961
查看次数

如何在INSERT ... ON CONFLICT中包含RETURNING中的排除行

我有这个表(由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)

我想批量插入大量使用数据INSERTON 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)

sql django postgresql upsert sql-returning

14
推荐指数
1
解决办法
1万
查看次数

插入行如果不存在导致竞争条件?

我正在使用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表.典型的情况是:

  1. 查询Feed网址,抓取Feed标头和所有当前内容
  2. 如果不存在,请将Feed标头插入feed_channel ...如果已存在,请抓取现有ID
  3. 对于每个Feed项,请插入feed_content表,并引用存储的通道ID

这是标准的"插入(如果尚未存在,但返回相关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

12
推荐指数
2
解决办法
2749
查看次数