Oracle: Sequenzen

Aus Wikibooks



Sequenzen sind Generatoren für numerische Werte, die automatisch hochgezählt werden und üblicherweise für Primärschlüsselwerte verwendet werden. Sinn einer Sequenz ist die Vermeidung des beliebten Anfängerfehlers "select max(id)+1 from xyz" zur Erzeugung des nächsten Primärschlüsselwertes.

Syntax zum Erzeugen einer Sequenz[Bearbeiten]

 CREATE SEQUENCE SEQUENCE_NAME
 INCREMENT BY 1  -- Schrittgröße beim Hochzählen
 START WITH 1    -- Startwert
 MINVALUE 1      -- Kleinster Wert
 MAXVALUE 999999 -- Größter Wert
 NOCYCLE / CYCLE -- wieder bei MINVALUE starten wenn MAXVALUE überschritten wurde
 CACHE 20
 NOORDER;

Verwenden von Sequenzen[Bearbeiten]

 select SEQUENCE_NAME.nextval from dual

liefert den nächsten Wert der Sequenz

 select SEQUENCE_NAME.currval from dual

liefert den aktuellen Wert der Sequenz, das heißt, genau den Wert, der beim letzten Aufruf von SEQUENCE_NAME.nextval zurückgeliefert wurde. SEQUENCE_NAME.currval kann erst aufgerufen werden, wenn vorher mindestens einmal SEQUENCE_NAME.nextval aufgerufen worden ist. Mit Currval kann man jedoch nur Werte abfragen, die in der eigenen Session erzeugt wurden. Selbst wenn in anderen parallel laufenden Sessions von der selben Sequence bereits weitere Werte generiert wurden, dann liefert Currval immer noch den zuletzt für die eigene Session generierten Wert. Wenn man in einer Session noch nicht mit Nextval einen Wert generiert hat, dann kann man auch nicht mit Currval den zuletzt generierten Wert abfragen.

Anwendungsbeispiel

 INSERT INTO tabelle1 (num, name) 
 VALUES (SEQUENCE_NAME.nextval, 'Test');

Oft steht man vor dem Problem, dass man den Wert, der soeben in die Datenbank geschrieben wurde weiterverwenden will, z.B. um einen Detaildatensatz in einer Untergeordneten Tabelle anzulegen, der über den Fremdschlüssel num verbunden ist. Hierzu gibt es 2 Möglichkeiten:

  1. Referenzieren über SEQUENCE_NAME.currval. Nachteil hierbei ist, dass insbesondere bei längeren Programmen oftmals nicht sichergestellt werden kann, dass der Wert der Sequenz unverändert ist.
  2. Innerhalb eines PL/SQL-Programms kann man den Wert über die RETURNING-Klausel direkt in eine Variable speichern:
 INSERT INTO tabelle1 (num, name) 
 VALUES (SEQUENCE_NAME.nextval, 'Test')
 RETURNING num INTO v_aktuellerSequenzwert;

Alternativ Speicherung in einer PL/SQL-Variablen:

 SELECT SEQUENCE_NAME.nextval INTO v_aktuellerSequenzwert FROM DUAL;

Beim Verwenden einer Sequenz kann nicht sichergestellt werden, dass die eingetragenen Werte lückenlos aufeinanderfolgen. Das liegt schon daran, dass immer mehrere Werte im Voraus generiert werden und in einem Cache gespeichert werden. Wenn die Datenbank heruntergefahren wird, dann gehen die im Cache gespeicherten Werte verloren.

Dictionary-View zu Sequenzen[Bearbeiten]

 select * from user_sequences;

Trigger (Vorlage) für eine Sequenz[Bearbeiten]

====(ersetze Platzhalter <% %>. ====

==== Zusätzlich (& nützlich): Timestamp's im Trigger. Siehe z.B.: --SELECT SYSDATE INTO :NEW.CHG_DATE FROM DUAL; // ggf. entfernen.====


 CREATE SEQUENCE SQ_<%tableName%> START WITH 1 INCREMENT BY 1 MINVALUE 1;
 / 
 CREATE OR REPLACE TRIGGER TS_<%tableName%> 
 BEFORE INSERT OR UPDATE 
 ON <%tableName%>
 REFERENCING NEW AS NEW OLD AS OLD 
 FOR EACH ROW 
 BEGIN
   IF (INSERTING) THEN 
     --SELECT SYSDATE INTO :NEW.CHG_DATE FROM DUAL; 
     --SELECT SYSDATE INTO :NEW.CRE_DATE FROM DUAL; 
     IF (:NEW.<%pkFieldName%> IS NULL) THEN 
       SELECT SQ_<%tableName%>.NEXTVAL INTO :NEW.<%pkFieldName%> FROM DUAL; 
     END IF; 
 
   ELSIF (UPDATING) THEN
     --SELECT SYSDATE INTO :NEW.CHG_DATE FROM DUAL;
   END IF;
 END;
 /

-- Kein Setzen von SEQUENCE_NAME.nextval in der Abfrage ist nun notwendig, Trigger z.B. TS_tabelle1 macht es nun beim Insert. 
-- Bsp.:
 INSERT INTO tabelle1 (name) VALUES ('Test'); 

-- Nachträgliches holen von gerade erstellten Id mit:
 SELECT  SQ_<%tableName%>.currval as value FROM dual;