Trigger bei INSERT zur Zeilenbegrenzung

Durmont

Neuer Benutzer
Beiträge
3
Hallo zusammen,

ich bin nicht nur neu in diesem Forum, sondern auch in Datenbanken und deren 'Programmierung'.

In meinem Anfängerdasein möchte ich folgendes Problem lösen:
In einer Tabelle soll bei INSERT automatisch ein Primary Key in eine dafür vorgesehene Spalte eintragen lassen. Dies soll aber nur gemacht werden, wenn eine bestimmte Anzahl von Zeilen noch nicht überschritten wurde (um z.B. nur eine Anzahl von Einträgen zuzulassen).

Angelegt habe ich eine Tabelle TEST mit den Spalten 'Nr' (als PK) und 'Name' (als String).
Dann lege ich eine Sequence und einen Trigger für den automatischen Primary Key an:

Code:
CREATE SEQUENCE test_seq;

CREATE OR REPLACE TRIGGER test_bi
BEFORE INSERT ON test
FOR EACH ROW
BEGIN
  SELECT test_seq.NEXTVAL
  INTO  :new.nr
  FROM  dual;
END;

Das funktioniert auch. Aber ich bekomme es nicht hin, diesen Trigger zu erweitern. Mein Ansatz ist, über die Gruppenfunktion COUNT die Anzahl der vorhandenen Zeilen zu ermitteln und zu testen, ob ein Wert überschritten wird. Ich bin mir auch nicht sicher, ob dies die richtige Vorgehensweise ist.

Wie kann ich dieses Problem halbwegs elegant lösen?
 
Werbung:
In meinem Anfängerdasein möchte ich folgendes Problem lösen:
In einer Tabelle soll bei INSERT automatisch ein Primary Key in eine dafür vorgesehene Spalte eintragen lassen. Dies soll aber nur gemacht werden, wenn eine bestimmte Anzahl von Zeilen noch nicht überschritten wurde (um z.B. nur eine Anzahl von Einträgen zuzulassen).

Du könntest die Sequence gleich so erzeugen, daß diese nur bis zu Deinem Maximalwert zählt. (PostgreSQL, sollte in Oraggle ähnlich gehen)

Code:
test=# create sequence ring_seq maxvalue 5 cycle;
CREATE SEQUENCE
test=*# create table ring (id int default nextval('ring_seq') primary key, val text);
CREATE TABLE
test=*# insert into ring (val) values ('test1');
INSERT 0 1
test=*# insert into ring (val) values ('test2');
INSERT 0 1
test=*# insert into ring (val) values ('test3');
INSERT 0 1
test=*# insert into ring (val) values ('test4');
INSERT 0 1
test=*# insert into ring (val) values ('test5');
INSERT 0 1
test=*# insert into ring (val) values ('test6');
ERROR:  duplicate key value violates unique constraint "ring_pkey"
DETAIL:  Key (id)=(1) already exists.
STATEMENT:  insert into ring (val) values ('test6');
ERROR:  duplicate key value violates unique constraint "ring_pkey"
DETAIL:  Key (id)=(1) already exists.


Was soll denn passieren, wenn die Tabelle voll ist?
 
Vielen Dank für die Antworten!
Ich möchte meinen Trigger später so nutzen, dass ich für die Primary Keys anderer Tabellen ebenfalls automatisch erzeugen kann. Daher kann ich keinen festen Wert festlegen, sondern direkt die Einträge einer Tabelle auf einen festen Wert überprüfen. Meine Test-Tabelle hat dann für einen bestimmten Zeitraum Gültigkeit und andere Einträge sollen dann nicht erlaubt sein. Sollte es doch versucht werden, könnte ich versuchen, den Fehler auszulesen. Damit habe ich mich aber noch nicht beschäftigt.
Jedenfalls erzeuge ich nach nach Ablauf des Zeitraums eine neue Tabelle, die wiederum auch nur eine begrenzte Anzahl an Einträgen zulassen soll.

Ich habe den Trigger jetzt so umgeschrieben:
Code:
CREATE OR REPLACE TRIGGER test_bir
BEFORE INSERT ON test
FOR EACH ROW
DECLARE
    v_sum NUMBER;

BEGIN
IF
    SELECT sum(nr) INTO v_sum FROM test;
    if v_sum < 6
THEN

  SELECT test_seq.NEXTVAL INTO :new.nr FROM dual;
END;

Der SQL developer gibt mir dann folgendes aus:

Warning: Ausführung mit Warnung abgeschlossen
TRIGGER test_bir Compiled.


Der Trigger funktioniert natürlich so nicht. Ein INSERT in die TEST-Tabelle schlägt damit fehl. Wie kann ich das denn lösen?
 
Werbung:
Ich sehe gerade, dass vor mir auch bereits so ein Anliegen hatte:

http://www.php.de/datenbanken/86766-datensaetze-tabelle-beschraenken.html

In deiner letzten Antwort sprichst du auch von einem Trigger. Wie hätte der in diesem Fall ausgesehen?

Bei Dir sehe ich 2 Probleme:

  • Du summierst und zählst nicht
  • new.nr ist an dieser Stelle schon zugewiesen. Wenn, dann mußt die das Insert komplett scheitern lassen.

Also folgendes funktioniert bei mir:

Code:
test=# create table durmont(i int);
CREATE TABLE
Time: 0,753 ms
test=*# create or replace function trigger_durmont() returns trigger as $$declare c int; begin select into c count(*) from durmont; if c < 10 then return new; else return null; end if; end;$$language plpgsql;
CREATE FUNCTION
Time: 0,456 ms
test=*# create trigger trg1 before insert on durmont for each row execute procedure trigger_durmont();
CREATE TRIGGER
Time: 0,300 ms

AAAAAAAAber:

Wenn 2 parallele Transaktionen sich darauf verlassen, dann geht es schief.

Was GENAU willst Du erreichen? Wenn da nur max. N Einträge drin sein dürfen dann mache einen Check-Constraint auf eine Spalte, die weder NULL noch kleiner 0 und auch nicht größer N sein darf und Unique sein muß.
 
Zurück
Oben