这是第二次尝试,因为我没有在第一个示例中添加足够的示例,因此已关闭。
我需要在Postgres中进行查询,如果现有数据包含无效数据,则会插入新项目。我想做这样的事情
if not exists( select * from table where field='value' ) then
insert into ...
end if;
我可以不用功能吗?
这是桌子
create table if not exists test_md (
id serial not null,
partition text not null,
version int not null,
data jsonb not null,
primary key (partition, version)
);
这里有一些数据
insert into test_md(partition, version, data)
values
('part one', 1, '{"k1": "v1", "k2": "v2"}'),
('part one', 2, '{"k1": "v1", "k2": "v2"}'),
('part two', 4, '{"k1": "v1", "k2": "v2"}'),
('part two', 5, '{"k1": "v1", "k2": "v2"}')
;
例如,我要插入数据集
{
'partition': 'part one',
'data': '{"k1": "v1", "k2": "v2"}'
}
如果partition
和data
与v2
记录相同,我什么也不做。在任何其他情况下,我都应添加一个max + 1
版本的新记录。
答案 0 :(得分:3)
事务看起来像这样(用PL / pgSQL中的DO
语句编写):
DO
$$DECLARE
r test_md;
new_version integer;
BEGIN
-- get the latest version and lock it
SELECT * INTO r
FROM test_md
WHERE partition = 'part one'
ORDER BY version DESC
FOR UPDATE
LIMIT 1;
-- if "data" has not changed, we are done
IF r.data = JSONB '{"k1": "v1", "k2": "v2"}' THEN
RETURN;
END IF;
new_version := coalesce(r.version, 0) + 1;
INSERT INTO test_md (partition, version, data)
VALUES ('part one', new_version, '{"k1": "v1", "k2": "v2"}');
END;$$;
当然,您可以编写与数据库函数或使用客户端代码相同的逻辑,但是请确保它在单个事务中运行。
答案 1 :(得分:1)
我认为这可以通过使用data modifying common table expression的单个语句来完成,尽管我不确定这是否比Laurenz的过程代码更有效:
with new_data (partition, data) as (
values ('part one', '{"k1": "v1", "k2": "v3"}'::jsonb)
), latest as (
select t.*
from test_md t
where t.partition = (select nd.partition from new_data nd)
order by version desc
limit 1
)
insert into test_md (partition, data, version)
select nd.partition,
nd.data,
(select coalesce(max(version), 0) + 1
from test_md md where md.partition = nd.partition)
from new_data nd
where not exists (select *
from latest e
where e.partition = nd.partition
and e.data = nd.data)