编写PostgreSQl函数的更好方法

时间:2012-12-05 09:51:41

标签: sql postgresql

这是我从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;

2 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分: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;