2016-09-03 23 views
2

請參閱下面的答案和編輯#1。但是,觸發器在PetaPoco/Npgsql下仍然失敗。如何強制新記錄僅在PostgreSQL中有序列值?

我在這裏缺少一些基本的東西。我需要確保任何記錄添加到該表中的順序沒有給出只有。即使當insertno聲明本身提供了orderno時,也應該包含這些信息。也就是說,

insert into returntooffice (chart_recid, returndate, torder, **orderno**) values (14982,'2016-11-09','2017-12-4 00:21:42.553508', **0**); 

insert into returntooffice (chart_recid, returndate, torder) values (14982,'2016-11-09','2017-12-4 00:21:42.553508'); 

應該既結果在接下來的orderno序列,而不是0這是一個orderno,什麼是實際發生的是,提供正在插入orderno(0) - 不是下一個序列值(8000)。我在這裏使用了一個觸發器,因爲實際組成的插入是由一個不遵循列上的postgreSQL DEFAULT子句的ORM實現的。

下面是詳細信息:

CREATE TABLE returntooffice 
(
    recid serial NOT NULL, 
    orderno integer NOT NULL, 
    chart_recid integer NOT NULL, 
    returndate date, 
    torder timestamp without time zone NOT NULL DEFAULT now(), 
    modified timestamp without time zone DEFAULT now(), 
    return_as_needed boolean, 
    is_deferred boolean, 
    CONSTRAINT returntooffice_pk PRIMARY KEY (recid), 
    CONSTRAINT returntooffice_chart_fk FOREIGN KEY (chart_recid) 
     REFERENCES charts (recid) MATCH SIMPLE 
     ON UPDATE CASCADE ON DELETE RESTRICT, 
    CONSTRAINT returntooffice_order_unqiue UNIQUE (orderno), 
    CONSTRAINT returntooffice_unqiue UNIQUE (chart_recid, torder) 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE returntooffice 
    OWNER TO postgres; 

CREATE TRIGGER get_next_order_number_trigger 
    BEFORE INSERT 
    ON returntooffice 
    FOR EACH ROW 
    EXECUTE PROCEDURE getnextorderno(); 

CREATE TRIGGER update_modified 
    BEFORE UPDATE 
    ON returntooffice 
    FOR EACH ROW 
    EXECUTE PROCEDURE update_modified(); 

CREATE SEQUENCE order_number_seq 
    INCREMENT 1 
    MINVALUE 1 
    MAXVALUE 9223372036854775807 
    START 6558 
    CACHE 1; 

ALTER TABLE order_number_seq 
    OWNER TO postgres; 

CREATE OR REPLACE FUNCTION getnextorderno() 
    RETURNS trigger AS 
$BODY$ 

BEGIN 
    NEW.orderno := nextval('order_number_seq'); 
    Return NEW; 
END; 

$BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 
ALTER FUNCTION getnextorderno() 
    OWNER TO postgres; 

編輯#1: 重命名觸發如下建議,讓一切的pgAdmin下正常工作,但仍無法在PetaPoco插入。任何想法爲什麼?

CREATE TRIGGER zzz_get_next_order_number_trigger 
    BEFORE INSERT 
    ON returntooffice 
    FOR EACH ROW 
    EXECUTE PROCEDURE getnextorderno(); 
+2

如果你確實創建了這樣的插入觸發器,存儲的值**將**始終從序列中取出。必須有其他事情正在進行。 –

+0

@a_horse_with_no_name同意。但即使直接使用PgAdmin,觸發器似乎也被忽略。我不明白。 :(如果我沒有記錯,這確實工作的PostgreSQL 9.3 –

回答

1

你可能有一個不同的問題,如在該表上也有BEFORE INSERT的行爲,這觸發後執行另一個觸發。請記住,對於相同行爲的觸發器執行順序按其名稱按字母順序選擇。


我測試了你的情況。(是的,在Postgres 9.5.4上,因爲你聲稱它在這個版本中不起作用。)一切工作正常。輸入值每次都會被order_number_seq中的下一個值覆蓋。

我們開始用的序列6558的值,因此:

postgres=# insert into returntooffice (orderno, chart_recid) values (0, 1); 
INSERT 0 1 
postgres=# insert into returntooffice (chart_recid) values (2); 
INSERT 0 1 
postgres=# insert into returntooffice (orderno, chart_recid) values 
      (nextval('order_number_seq'::regclass), 3); 
INSERT 0 1 

和輸出預期是:

postgres=# select recid, orderno, chart_recid from returntooffice; 
recid | orderno | chart_recid 
-------+---------+------------- 
    1 | 6558 |   1 
    2 | 6559 |   2 
    3 | 6561 |   3 

重現 「問題」我必須通過刪除約束來修改創建腳本,替換不同語句的執行順序並刪除不必要的部分。這是它:

CREATE TABLE returntooffice 
(
    recid serial NOT NULL, 
    orderno integer NOT NULL, 
    chart_recid integer NOT NULL, 
    returndate date, 
    torder timestamp without time zone NOT NULL DEFAULT now(), 
    modified timestamp without time zone DEFAULT now(), 
    return_as_needed boolean, 
    is_deferred boolean 
) 
WITH (
    OIDS=FALSE 
); 

CREATE OR REPLACE FUNCTION getnextorderno() 
    RETURNS trigger AS 
$BODY$ 

BEGIN 
    NEW.orderno := nextval('order_number_seq'); 
    Return NEW; 
END; 

$BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 

-- Trigger: get_next_order_number_trigger on returntooffice 

-- DROP TRIGGER get_next_order_number_trigger ON returntooffice; 

CREATE TRIGGER get_next_order_number_trigger 
    BEFORE INSERT 
    ON returntooffice 
    FOR EACH ROW 
    EXECUTE PROCEDURE getnextorderno(); 


CREATE SEQUENCE order_number_seq 
    INCREMENT 1 
    MINVALUE 1 
    MAXVALUE 9223372036854775807 
    START 6558 
    CACHE 1; 
+0

更改觸發器名稱確實與pgAdmin的工作,但是這PetaPoco下仍然失敗 - 但是這是一個不同的問題,謝謝。 –

1

兩個替代凌亂觸發器。首先是操縱角色權限。

create table t (i serial, s text); 

撤銷表上的所有權限由相關角色:

revoke all on t from test; 

格蘭特只選擇所有所有列,但序列中的一個

grant select on t to test; 

格蘭特:

grant all (s) on t to test; 

補助金使用o NLY的序列:

revoke all on t_i_seq from test; 
grant usage on t_i_seq to test; 

現在,角色不能插入序列列:

insert into t (s) values ('a'); 
INSERT 0 1 
insert into t (i,s) values (10,'a'); 
ERROR: permission denied for relation t 

第二個選擇是簡單的。僅授予選擇角色:

revoke all on t from test; 
grant select on t to test; 

由於表所有者創建的安全定義者「插入函數:

create function f(_s text) 
returns t as $$ 

    insert into t (s) values (_s) 
    returning *; 

$$ language sql security definer; 

角色只能使用功能接入。

相關問題