Rule erstellen über zwei Tabellen

Ich hätte nochmal eine Frage. Ich habe folgende zwei Tabellen:

  • verein(VereinID,Verein)
  • information(InfoID,Information,Stadion,VereinID)

Danach habe ich eine View erstellt:

  • vereininfo(InfoID,Information,Stadion,Verein)

Wenn ich mir nun folgende Rule dazu erstelle, kann ich zwar einen neuen Datensatz erstellen, dieser wird mir jedoch nicht in der View angezeigt:

CREATE RULE vereininfo_insert AS
ON INSERT TO vereininfo
DO INSTEAD(
INSERT INTO information(Information,Stadion) VALUES (NEW.Information,NEW.Stadion); 
INSERT INTO verein(Verein) VALUES (NEW.Verein) WHERE 
);

Wenn ich mir den Inhalt der Tabelle information anzeigen lasse, sehe ich das der Datensatz zwar erstellt wird, er jedoch bei VereinID nichts einträgt und damit den Datensatz auch nicht anzeigen kann. Irgendwie habe ich grade keine Idee wie ich hier weiterkommen kann. Kann man dies überhaupt mit Hilfe einer Rule hinbekommen?


EDIT: Was ich vielleicht noch hinzufügen sollte. Wenn der Verein schon vorhanden ist, soll der Verein mit der ID benutzt werden, ansonsten soll er mit einer neuen ID erstellt werden. Sehe grade das in der Tabelle Verein der Wert auf jedenfall ankommt, aber doppelt drin ist. Habe der Variable Verein nun mal UNIQUE hinzufügt, dann sollte das schon reichen, oder?

Nutze lieber TRIGGER als RULEs, RULEs sind in manchen Dingen problematisch und viele raten von deren Benutzung ab. Auf diversen Mailinglisten gibt es Details dazu.

Besser: TRIGGER. Die gehen auch auf VIEWs, zumindest in aktuellen Versionen (ab 9.1 oder 9.2, ich weiß es nicht…)

test=# create table verein(vereinid serial primary key, verein text);
NOTICE:  CREATE TABLE will create implicit sequence "verein_vereinid_seq" for serial column "verein.vereinid"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "verein_pkey" for table "verein"
CREATE TABLE
Time: 41,926 ms
test=*# create table information(infoid serial primary key, info text, stadion int, vereinid int references verein);
NOTICE:  CREATE TABLE will create implicit sequence "information_infoid_seq1" for serial column "information.infoid"
ERROR:  relation "information" already exists
Time: 1,151 ms
test=*# create view view_verein as select i.infoid, i.info, i.stadion, v.verein from information i left join verein v on i.vereinid=i.vereinid;
CREATE VIEW
Time: 1,300 ms
test=*# create or replace function my_insert() returns trigger as $$declare c int;begin insert into information(info, stadion) values (new.info, new.stadion); select into c count(*) from verein where verein = new.verein; if c=0 then insert into verein (verein) values (new.verein); end if; return new; end;$$language plpgsql;
CREATE FUNCTION
Time: 0,510 ms
test=*# create trigger trg_insert instead of insert on view_verein for each row execute procedure my_insert();
CREATE TRIGGER
Time: 0,471 ms
test=*# insert into view_verein values (1, 'info1',1,'dynamo');
INSERT 0 1
Time: 1,026 ms
test=*# insert into view_verein values (2, 'info2',1,'dynamo');
INSERT 0 1
Time: 0,375 ms
test=*# insert into view_verein values (3, 'info3',1,'sonstwas');
INSERT 0 1
Time: 0,409 ms
test=*# select * from view_verein ;
 infoid | info  | stadion | verein
--------+-------+---------+--------
      6 | info1 |       1 |
      7 | info2 |       1 |
      8 | info3 |       1 |
(3 rows)

Time: 0,308 ms
test=*#

Mal so als Fingerübung :wink:

Andreas

Mit Trigger hatte ich mir das auch schonmal angesehen. Aber auch bei deiner “Lösung” wird in der View kein Wert bei Verein angezeigt. Das Problem, dass ein Verein nochmal neu eingetragen wird, geht nun nicht mehr, was auch gut ist, aber der Verein selber fehlt leider noch in der View. Da komme ich grade auch irgendwie nicht dran?

Ja, Fehler von mir, ich trage da in die verein-Tabelle die ID nicht ein, damit klappt der JOIN für die VIEW nicht. Sorry.

Aber hey, das zu fixen überlasse ich dir jetzt zur übung :wink:

Andreas

Ich probiere mich grade noch weiter, also wenn es klappt melde ich mich trotzdem nochmal. Noch hat es bei mir nicht geklappt. Nun habe ich aber doch nochmal eine Frage zu der Triggerfunktion. Ich habe aber nochmal eine Verständnisfrage:

select into c count(*) from verein where Verein = new.Verein;

In dieser Zeile wird einfach nur überprüft ob der Verein schon vorhanden ist. Wenn ja macht er nichts, ansonsten trägt er ihn neu ein. Habe ich das richtig verstanden?

Absolut!


Andreas

Ich habe es nun, nach langem probieren, folgendermaßen gelöst:

CREATE OR REPLACE FUNCTION verein_insert() RETURNS TRIGGER
LANGUAGE plpgsql 
AS $function$ 
declare c int;
declare d int;
    BEGIN 
    select into c count(*) from verein where Verein = new.Verein; 
    if c=0 then 
        insert into verein values (Default,new.Verein); 
    END IF; 
    SELECT INTO d VereinID from verein WHERE Verein = new.Verein;
    INSERT INTO information(Info, Stadion,VereinID) values (new.Info, new.Stadion,d); 
    return new; 
    end;
$function$;

Wüsste gerne ob das so ganz ok ist, oder doch eher zu unsauber?

Auf jedenfall schonmal vielen Dank für die Hilfe!

Das d könnte man weglassen und die dazu nötige Abfrage in die andere Abfrage einbauen. Man könnte auch für c gleich die ID abfragen. Falls man das Insert machen muß, mit returning id arbeiten. Dann hätte man die nötige id gleich, müßte nur die prüfung c=0 auf is null ändern.

Andreas


Andreas