如果条目不存在,我想将数据插入到多个表中。
在我的示例中,我有一个餐厅表、一个位置表、一个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
如何使用简单的 SQL 执行此操作?
最佳答案
在 Postgres 9.1 或更高版本 中,您可以使用 data-modifying CTEs使其快速、安全、简单和优雅:
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;
第一个 INSERT
仅在未找到“restaurantname”时执行。如果多个查询应在同一实例中尝试相同的查询,则会出现超小的竞争条件。如果您对 restaurant.name
有一个 UNIQUE
约束(就像您应该从您的描述中判断的那样),可能发生的最坏情况是在并发查询中只有第一个会成功,而其他人以独特的违规行为返回(什么都不做)。然而,您很可能永远不会看到这种情况,因为它不太可能发生。
RETURNING
子句返回自动生成的 rest_id
- 我假设 rest_id
是一个序列列。
以下 INSERT
查询仅在第一个成功时生成行。
以简单的 INSERT
结束本系列。
对于 PostgreSQL 8.1,我会编写一个 plpgsql 函数来实现相同的目的。
但是,真的,你最好升级到 current version .
关于sql - 如果条目不存在,则使用 PostgreSQL 进行多次插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12157805/