Postgres查询中的逻辑

时间:2020-11-11 17:39:10

标签: sql postgresql

这是第二次尝试,因为我没有在第一个示例中添加足够的示例,因此已关闭。

我需要在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"}'
}

如果partitiondatav2记录相同,我什么也不做。在任何其他情况下,我都应添加一个max + 1版本的新记录。

2 个答案:

答案 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)