postgres 中的条件 INSERT INTO 语句

Posted

技术标签:

【中文标题】postgres 中的条件 INSERT INTO 语句【英文标题】:Conditional INSERT INTO statement in postgres 【发布时间】:2013-03-20 13:30:34 【问题描述】:

我正在为模拟航空公司预订数据库编写预订程序,我真正想做的是这样的:

IF EXISTS (SELECT * FROM LeadCustomer 
    WHERE FirstName = 'John' AND Surname = 'Smith') 
THEN
   INSERT INTO LeadCustomer (Firstname, Surname, BillingAddress, email) 
   VALUES ('John', 'Smith', '6 Brewery close,
            Buxton, Norfolk', 'cmp.testing@example.com');

但是 Postgres 不支持 IF 不加载 PL/pgSQL 扩展的语句。我想知道是否有办法做到这一点,或者在这一步中是否需要进行一些用户交互?

【问题讨论】:

为什么不直接加载 PL/pgSQL 扩展呢? @MattBall:在实验室计算机上安装 postgres。使用该扩展不在规范中。 【参考方案1】:

该特定命令可以这样完成:

insert into LeadCustomer (Firstname, Surname, BillingAddress, email)
select 
    'John', 'Smith', 
    '6 Brewery close, Buxton, Norfolk', 'cmp.testing@example.com'
where not exists (
    select 1 from leadcustomer where firstname = 'John' and surname = 'Smith'
);

它将插入选择语句的结果,select 只会在该客户不存在时返回一行。

【讨论】:

我认为这里有一场(非常小的)比赛? select子查询运行,返回0行,另一个线程发生insert,然后发生LeadCustomer insert? @Kevin 将引发主键异常,应用程序将决定做什么。 我很困惑,这个问题在任何地方都没有提到主键。如果 (firstname, surname) 上有一个主键,为什么不先尝试插入? @Kevin 我会先尝试插入。问题只是关于语法。 有没有办法像这样插入多行?【参考方案2】:

自 9.5 版本起包含 pgsql upsert,使用 INSERT ... ON CONFLICT DO UPDATE ...

下面的答案不再相关。几年后发布了 Postgres 9.5,并提供了更好的解决方案。

如果不添加新功能,Postgres 没有“upsert”功能。 您需要做的是运行选择查询并查看是否有匹配的行。如果你这样做,然后插入它。

我知道你并不完全想要一个 upsert,但它几乎是一样的。

【讨论】:

即使发生冲突(尝试插入时),这也会继续增加自动递增的 id “检查结果,有条件地插入”容易出现竞争条件:如果你有两个线程同时在做,你可以得到两个插入。 @CharlesDuffy 不在事务中(如果选择更新,则不在事务中)

以上是关于postgres 中的条件 INSERT INTO 语句的主要内容,如果未能解决你的问题,请参考以下文章

MySQL中的insert ignore into, replace into等的一些用法小结(转)

有条件的 INSERT INTO MySQL - 不存在的地方

Oracle中如何用一条insert into 语句插入多条数据 如: insert into 表 values(多条数据)????????

数据库系列—— merge into用法

是否可以使用 Doctrine QueryBuilder 构建 INSERT INTO SELECT 查询?

MySQL 关于表复制 insert into 语法的详细介绍