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