Ste*_*Arn 3 sql postgresql common-table-expression sql-insert
如果条目不存在,我想将数据插入到多个表中.
在我的情况下,我有一个餐厅餐桌,一个位置表,一张foodtype桌子和一些帮助表,如restaurant_location和restaurant_foodtype.现在我想插入一个新的餐厅条目,如果条目不存在,则填写位置和食物类型信息.
所以类似于:
IF NOT (select 1 from restaurant where name='restaurantname') THEN
INSERT INTO restaurant(x,y) VALUES (valuex,valuey);
INSERT INTO restaurant_location(rest_id,..) VALUES (rest_id,..);
INSERT INTO restaurant_foodtype(rest_id,..) VALUES (rest_id,..);
...
END IF
Run Code Online (Sandbox Code Playgroud)
我怎么能用简单的SQL做到这一点?
在Postgres 9.1或更高版本中,您可以使用数据修改CTE来实现快速,安全,简单和优雅:
WITH x AS (
INSERT INTO restaurant(name, x, y)
SELECT 'restaurantname', valuex, valuey
WHERE NOT EXISTS (SELECT 1 FROM restaurant WHERE name = 'restaurantname')
RETURNING rest_id -- returns auto-generated id (from sequence)
)
, y AS (
INSERT INTO restaurant_location(rest_id, ...)
SELECT rest_id, ...
FROM x -- only produces rows after a successful INSERT
)
--- more chained INSERTs here?
INSERT INTO restaurant_foodtype(rest_id, ...)
SELECT rest_id, ...
FROM x;
Run Code Online (Sandbox Code Playgroud)
第一个INSERT仅在未找到'restaurantname'时执行.如果多个查询在同一个实例中尝试相同,则存在超小的竞争条件.如果你有一个UNIQUE约束restaurant.name(就像你应该从你的描述判断),可能发生的最坏情况是,在同意的查询中,只有第一个会成功,而其他人会以唯一的违规行为(无所事事)返回.但是,你很可能永远不会看到这一点,因为它不太可能发生.
该RETURNING子句返回自动生成的rest_id- 我假设rest_id是一个串行列.
INSERT如果第一个查询成功,则以下查询仅生成行.
完成系列是一个平原INSERT.
使用PostgreSQL 8.1我会编写一个plpgsql函数来实现相同的功能.
但是,实际上,您最好升级到当前版本.