我有一個 INSTEAD OF 觸發器,但是當我插入視圖時 PostgreSQL 仍然抱怨
我創建了一個視圖和一個 INSTEAD OF 觸發器,用於從該視圖中插入/更新/刪除。現在我嘗試向視圖中插入一些數據,而 PostgreSQL 返回以下錯誤(捷克語翻譯:“chyba”=“error”,“Stav SQL”=“SQL state”):
ERROR: cannot insert into view "ukaz_lok" DETAIL: Views that return columns that are not columns of their base relation are not automatically updatable. HINT: To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule. ********** Chyba ********** ERROR: cannot insert into view "ukaz_lok" Stav SQL: 55000
這發生在其他一些 INSTEAD OF 觸發器之前 - 這個錯誤只持續了一段時間(幾個小時?我不記得確切),然後 PostgreSQL 找到了觸發器。我嘗試了各種方法(更改觸發器、刪除所有觸發器和視圖並重新創建它們等),但我不確定什麼有效,只是某些有效。那麼究竟如何讓PostgreSQL辨識觸發器呢?
我在 Windows XP 32 位上有 PostgreSQL 9.3.4 和 pgAdmin III 1.18.1。以防萬一它是由程式碼中的某些東西引起的,這裡是:
CREATE TABLE lokalita ( kod_lok text NOT NULL, nazev text NOT NULL, katastr text NOT NULL, presnost integer NOT NULL, stred geometry(Point,4326) NOT NULL, rozsah geometry(Polygon,4326), CONSTRAINT pk_lok PRIMARY KEY (kod_lok), CONSTRAINT fk_pro_pr FOREIGN KEY (presnost) REFERENCES pro_presnost (id) MATCH SIMPLE ON UPDATE CASCADE ON DELETE CASCADE ) WITH ( OIDS=FALSE ); CREATE OR REPLACE VIEW ukaz_lok AS SELECT l.kod_lok AS _kod, l.nazev AS _nazev, l.katastr AS _katastr, l.presnost AS _presnost, 50.0 AS _sirka, 14.0 AS _delka FROM lokalita l; CREATE OR REPLACE FUNCTION osetri_lok() RETURNS trigger AS $$ BEGIN IF TG_OP = 'INSERT' THEN INSERT INTO lokalita (kod_lok, nazev, katastr, presnost, stred) VALUES( NEW._kod, NEW._nazev, NEW._katastr, NEW._presnost, ST_GeomFromText('POINT('|| NEW.delka ||' '|| NEW.sirka ||')', 4326) ); ELSIF TG_OP = 'UPDATE' THEN UPDATE lokalita SET nazev = NEW._nazev, katastr = NEW._katastr, presnost = NEW._presnost, stred = ST_GeomFromText('POINT('|| NEW.delka ||' '|| NEW.sirka ||')', 4326) WHERE lod_lok = OLD._kod; ELSIF TG_OP = 'DELETE' THEN DELETE FROM lokalita WHERE kod_lok = OLD._kod; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER osetri_lok INSTEAD OF DELETE ON ukaz_lok FOR EACH ROW EXECUTE PROCEDURE osetri_lok(); INSERT INTO ukaz_lok (_kod, _nazev, _katastr, _presnost, _delka, _sirka) VALUES( 'Kote2', 'Kotěhůlky 2', 'Kotěhůlky', 2, 14.060316, 50.432044 );
您的程式碼中有一個觸發器
INSTEAD OF DELETE
,但沒有INSTEAD OF
INSERT
。也創造它。您可以將其設為觸發器
INSTEAD OF INSERT OR DELETE
,但我建議將觸發器函式用於INSERT
和DELETE
單獨的觸發器。簡化功能程式碼(不再需要IF TG_OP =
等)。還要考慮手冊中的這句話:
行級
INSTEAD OF
觸發器應該返回NULL
以指示它沒有修改視圖的基礎基表中的任何數據,或者它應該返回傳入的視圖行(NEW
用於INSERT
和UPDATE
操作的OLD
行,或用於DELETE
操作的行)。非空返回值用於表示觸發器在視圖中執行了必要的數據修改。這將導致受命令影響的行數的計數增加。僅對於INSERT
和UPDATE
操作,觸發器可以NEW
在返回之前修改行。這將更改INSERT RETURNING
or返回的數據UPDATE RETURNING
,並且當視圖顯示的數據與提供的數據不完全相同時很有用。