Information ausblenden
Willkommen im Forum für alle Datenbanken! Registriere Dich kostenlos und diskutiere über DBs wie Mysql, MariaDB, Oracle, Sql-Server, Postgres, Access uvm

Trigger bei INSERT zur Zeilenbegrenzung

Dieses Thema im Forum "Oracle" wurde erstellt von Durmont, 19 Juni 2014.

  1. Durmont

    Durmont Neuer Benutzer

    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?
     
  2. akretschmer

    akretschmer Datenbank-Guru

    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?
     
  3. akretschmer

    akretschmer Datenbank-Guru

  4. Durmont

    Durmont Neuer Benutzer

    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?
     
  5. Durmont

    Durmont Neuer Benutzer

  6. akretschmer

    akretschmer Datenbank-Guru

    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ß.
     
Die Seite wird geladen...

Diese Seite empfehlen

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies.
    Information ausblenden