Postgres中的条件INSERT INTO语句

77

我正在编写一个模拟航空订票系统的预订流程,我真正想做的是像这样:

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不支持没有加载PL/pgSQL扩展的IF语句。我想知道是否有一种相当的方法来做这个或者在这一步中是否只需要一些用户交互?


为什么不直接加载PL/pgSQL扩展呢? - Matt Ball
@MattBall:正在处理实验室电脑上的Postgres安装。使用该扩展不在规范中。 - The General
3个回答

145

那个特定的命令可以像这样执行:

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只有在该客户不存在时才会返回一行。


3
这里是否存在一个(非常小的)竞争关系?选择子查询运行后返回0行,然后在另一个线程中插入数据,之后进行LeadCustomer插入操作? - Kevin Burke
@Kevin 会引发主键异常,应用程序将决定如何处理。 - Clodoaldo Neto
5
我有点困惑,这个问题似乎没有提到主键。如果在(名字,姓氏)上有一个主键,为什么不先尝试插入呢?请问您的意思是什么? - Kevin Burke
1
@Kevin 我会先尝试插入。问题只涉及语法。 - Clodoaldo Neto
4
有没有一种像这样插入多行的方法? - Callum Rogers
显示剩余3条评论

7
自9.5版本以来,pgsql已经包含了upsert功能,使用INSERT ... ON CONFLICT DO UPDATE ...
下面的答案已不再相关。几年后发布了更好的解决方案Postgres 9.5。
如果没有添加新功能,Postgres没有"upsert"功能。
你需要运行select查询并查看是否有匹配的行。如果是,则插入它。
我知道你不想要一个完全的upsert,但它基本上是一样的。

2
即使存在冲突(因为尝试插入),此操作将不断增加自动增量ID。 - rohanagarwal
“检查结果并有条件地插入”容易出现竞态条件:如果同时有两个线程执行此操作,则可能会出现两次插入。 - Charles Duffy
@CharlesDuffy 不在事务中(或者如果是select for update,则不在) - Kamil Tomšík

-4

-- 使用以下格式将数据插入任何表格 --

创建用户表 ( user_id varchar(25) primary key, phone_num numeric(15), failed_login int not null default 0, Login time timestamp );

将数据插入用户表 INSERT INTO USER(user_id, phone_num, failed_login, Login time) VALUES ('12345','123456789','3',' 2021-01-16 04:24:01.755');


1
目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何撰写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接