web-dev-qa-db-ja.com

INSTEAD OFトリガーがありますが、ビューに挿入している間もPostgreSQLは文句を言います

ビューと、そのビューから挿入/更新/削除するためのINSTEAD OFトリガーを作成しました。今、私はビューにいくつかのデータを挿入しようとしました、そしてPostgreSQLは次のエラーを返します(チェコ語からの翻訳: "chyba" = "エラー"、 "Stav SQL" = "SQL状態"):

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にトリガーを正確に認識させるにはどうすればよいですか?

私はPostgreSQL 9.3.4とpgAdmin III 1.18.1をWindowsにインストールしていますXP 32ビット。コード内の何かが原因で発生した場合に備えて、ここに示します。

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
);
3
Pavel V.

コードにトリガーINSTEAD OF DELETEがありますが、INSTEAD OFINSERTはありません。それも作成します。

あなたはそれをトリガー_INSTEAD OF INSERT OR DELETEにすることができますが、私はINSERTDELETEのための別々のトリガー関数と別々のトリガーを提案するでしょう。関数コードを簡略化します(IF TG_OP =などは必要ありません)。

このマニュアルからの引用 も考慮してください:

行レベルのINSTEAD OFトリガーは、NULLを返して、ビューの基礎となるベーステーブルのデータを変更しなかったことを示すか、渡されたビュー行(NEW行)を返す必要がありますINSERTおよびUPDATE操作の場合、またはOLD操作の場合はDELETE行)。 null以外の戻り値は、トリガーがビューで必要なデータ変更を実行したことを示すために使用されます。これにより、コマンドの影響を受ける行数のカウントが増加します。 INSERTおよびUPDATE操作の場合、トリガーはNEW行を変更してからそれを返す場合があります。これにより、INSERT RETURNINGまたはUPDATE RETURNINGによって返されるデータが変更され、提供されたものとまったく同じデータがビューに表示されない場合に役立ちます。

8