2012-12-05 81 views
1

這是我從MS SQLServer轉換到PostgreSQL的存儲過程。有沒有更好的方式在Postgres中編寫它。另外什麼應該是最佳做法?任何幫助將不勝感激。編寫PostgreSQl函數的更好方法

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

你到底想達到什麼目的?你爲什麼不使用'SEQUENCE'?你在尋找無間隙序列嗎? –

回答

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; 
1

你的做法是根本性的缺陷,在數據庫的讀一致性機制可能會導致多個同時發生的進程讀取從STD_SERIAL_NOS相同的價值觀,並嘗試插入/更新這些值。

在Postgres(或Oracle)中生成鍵值的正確方法是使用序列對象,也可能使用自動填充主鍵列的觸發器。

想想吧,您使用的方法可能在任何數據庫系統中都存在缺陷。

+0

來自SQLServer的原始存儲過程。 http://pastebin.com/f2Uxum46 –

+0

無論RDBMS首次實施,它都存在根本性缺陷。 –

+0

@DavidAldridge:在SQL Server中不一定存在缺陷。在默認安裝中,讀者和作者會相互阻塞。因此,一旦執行了遊標中的選擇,對該數據的任何更新都將被阻塞,直到事務提交。 –