1

这是我从 MS SQLServer 转换为 PostgreSQL 的存储过程。有没有更好的方法在 Postgres 中编写它。还有什么应该是最佳实践?任何帮助将不胜感激。

create or replace function GenSerialNo_SP1(tname character varying) returns AS $$

--declare @PK bigint
declare totalRec bigint;
declare getRec bigint;
Begin

    --set @PK = 1
    set totalRec=-1;

    for getRec inselect coalesce(primary_key,0) from STD_SERIAL_NOS 
   where table_name = tname
    loop
    open  getRec;
    fetch next from getRec into totalRec;
    close getRec;
    deallocate getRec;
    end loop;
    if totalRec = -1 then

        insert into STD_SERIAL_NOS (TABLE_NAME, PRIMARY_KEY) values (tname, 1);

    else

        update STD_SERIAL_NOS set primary_key = primary_key +1 
           where table_name = tname;

    end if;

end;
$$ language plpgsql;
4

2 回答 2

1

您的方法存在根本缺陷,因为数据库的读取一致性机制可能导致多个同时进程从 STD_SERIAL_NOS 读取相同的值并尝试插入/更新这些值。

在 Postgres(或 Oracle)中生成键值的正确方法是使用序列对象,并且可能使用触发器来自动填充主键列。

想一想,您使用的方法在任何数据库系统中都可能存在缺陷。

于 2012-12-05T09:58:52.207 回答
1

它看起来像一个UPSERT,但您不需要任何游标来实现它。

假设 上有一个唯一索引STD_SERIAL_NOS.table_name,一个(希望)正确的版本(包括处理插入时的竞争条件)将是:

create or replace function GenSerialNo_SP1(tname character varying) returns void
as $$
begin
  loop
   begin
     update STD_SERIAL_NOS set primary_key = primary_key +1 
        where table_name = tname;
     exit when found; -- exit loop if the row exists, otherwise insert it
     insert into STD_SERIAL_NOS (TABLE_NAME, PRIMARY_KEY)
        values(tname,1);
   exception  WHEN unique_violation THEN
     -- the insert conflicts, let's go back to the update in the next loop iteration
   end;
  end loop;

end;
$$ language plpgsql;
于 2012-12-05T13:00:10.387 回答