|
Leider gibt es in ORACLE keinen Datentypen AUTOINCREMENT, wie er in anderen Datenbanken (z.B. mysql) existiert. Sogar MS Access ist in der Lage, Spalten - typischerweise Primärschlüsselspalten - einen automatisch hochzählenden Wert zu vergeben. In ORACLE kann man diesen Datentypen lediglich "simulieren", in dem man eine Sequence und einen Trigger benutzt. Wenn man sein Datenmodell dahingehend überarbeiten möchte, bedeutet das, für jede auto-increment-Spalte eine eigene Sequence und einen eigenen Trigger zu programmieren. Das ist mir zuviel Arbeit. Anstelle dessen habe ich mir ein kleines PL/SQL-Programm geschrieben, das mir die Arbeit abnimmt und demonstriert, dass dynamische Programmierung nicht nur dynamisches SQL bedeutet, sondern auch Programme dynamisch generiert werden können.
FunktionDie Procedure make_ai wird gefüttert mit dem Tabellennamen und der Spalte, die zum Primärschlüssel gemacht werden soll. Für die angebene Spalte wird ein Primary Key Constraint erzeugt, eine Sequence namens seq_<tabellenname> angelegt, die bei eins anfängt zu zählen und um eins inkrementiert. Zuguterletzt wird ein Trigger angelegt namens bi_<tabellenname>_autoinc, der bei jedem Insert-Versuch den nächsten Sequencewert selektiert und ihn in die Primärschlüsselspalte einfügt. Grenzen/Fehlverhalten- Das Primärschlüssel-Constraint wird nicht benannt sondern kriegt einen ORACLE-eigenen Namen
- Nur einspaltige Primärschlüssel werden erzeugt
- Der Datentyp der Primärschlüsselspalte wird nicht geprüft. Sollte es sich um VARCHAR handeln, funktioniert die Triggeraktion dank automatischer Typkonvertierung weiterhin, spätestens bei DATE o.ä. löst der Trigger einen unbehandelten Fehler aus
- Existiert schon ein Primärschlüssel, wird dieser nicht verändert, aber das Programm fährt fort mit dem Anlegen der Sequence und legt einen Trigger für die angegebene Spalte an. Das kann man auch als Feature benutzen, so daß auch NICHT-Primärschlüsselspalten mit dieser Art "autoincrement" versehen werden können
- Existiert eine Sequence mit entspr. Namen bereits, wird diese verwendet und nicht neu angelegt
- Ein eventueller Trigger mit gleichem Namen wird kommentarlos überschrieben
create or replace procedure make_ai (tname varchar2, cname varchar2) is begin begin execute immediate 'alter table '||tname|| ' add primary key('||cname||')'; exception when others then -- Wenn der Primärschlüssel schon existiert, mach weiter if sqlcode=-2260 then null; else raise; end if; end; begin execute immediate 'create sequence seq_'||tname|| ' start with 1 increment by 1'; exception when others then -- wenn die Sequence schon existiert, mach weiter if sqlcode=-955 then null; else raise; end if; end; begin execute immediate 'create or replace trigger bi_'||tname|| '_autoinc before insert on '||tname||' for each row'|| ' begin select seq_'||tname||'.nextval into :new.'|| cname||' from dual;'||' end;'; exception when others then raise; end; end; /
|