Was sind SEQUENCEs?
Eine der wichtigsten SEQUENCE
s hatten wir euch bereits im letzten Randori vorgestellt. Generell ist ein SEQUENCE
-Objekt die Verallgemeinerung des IDENTITY
-Attributs. Denn während das IDENTITY
-Attribut dafür sorgt, dass jede neue Zeile eine neue Zahl zugewiesen bekommt, ist das SEQUENCE-Objekt ein Objekt, das Reihen von Zahlen erzeugt. Dabei ist es anders als das IDENTITY
-Attribut nicht an ein anderes Datenbankobjekt (also eine Tabelle) gebunden, sondern ist ein eigenes Objekt, das abgefragt und verwendet werden kann.
Wie könnt ihr mit SEQUENCEs arbeiten?
Zunächst müsst ihr euch ein SEQUENCE
-Objekt in einem neuen Schema definieren. Das tut ihr mit dem CREATE SEQUENCE
-Befehl:
CREATE SCHEMA Test GO CREATE SEQUENCE Test.SeqCount START WITH 1 INCREMENT BY 1; GO
Nun habt ihr also das SEQUENCE
-Objekt erzeugt, die Parameter waren ähnlich wie bei der IDENTITY
-Eigenschaft der Startwert (also eins) und das Inkrement, also der Wert um den jeweils erhöht wird (also wieder eins). Um euch den jeweils nächsten Wert aus der Sequenz zu holen, führt einige Male das folgende Statement aus:
SELECT NEXT VALUE FOR Test.SeqCount
Ihr seht, dass bei jeder Abfrage der Wert um eins steigt. Anders als bei der IDENTITY
-Eigenschaft einer Spalte habt ihr hier aber noch andere Optionen beim Anlegen einer Sequenz. Legen wir nun also eine zweite Sequenz an:
CREATE SEQUENCE Test.SeqCountMax START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 5; GO
Dieser Sequenz habt ihr neben dem Startwert auch einen Minimalwert (der in diesem Fall gleich dem Startwert ist) und einen Maximalwert mitgegeben. Holt ihr euch nun sechsmal den nächsten Wert der Sequenz, so überschreitet sie den Maximalwert:
SELECT NEXT VALUE FOR Test.SeqCountMax
Ihr erhaltet bei den ersten fünf Aufrufen die Werte 1 bis 5 zurück, beim sechsten Aufruf aber eine Fehlermeldung, dass die Sequenz ihren Maximalwert erreicht hat. Was kann dagegen getan werden? Einfach: anders als bei der Identity-Eigenschaft können Sequenzen so erstellt werden, dass sie Werte “recyceln”:
CREATE SEQUENCE Test.SeqCountCycle START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 5 CYCLE; GO
Wenn ihr nun sechsmal den nächsten Wert abruft, so erhaltet ihr beim sechsten Aufruf keinen Fehler, sondern wieder den Wert 1:
SELECT NEXT VALUE FOR Test.SeqCountCycle
Ihr könnt aber nicht nur auf den Startwert zurück springen, sondern auch auf andere Werte, beispielsweise können wir in einer Sequenz auch negative Werte ausgeben:
CREATE SEQUENCE Test.SeqCountCycleNeg START WITH 1 INCREMENT BY 1 MINVALUE -5 MAXVALUE 5 CYCLE; GO
Ruft ihr nun sechsmal den nächsten Wert der Sequenz ab, so erhaltet ihr beim sechsten Aufruf den Wert -5, der dann bis +5 durch läuft um dann wieder zu -5 zu springen:
SELECT NEXT VALUE FOR Test.SeqCountCycleNeg
Im Übrigen kann euer INCREMENT BY
auch negativ sein, dann zählt die Sequenz die Werte nicht nach oben, sondern runter, ihr könnt also eine Art “Countdown” bauen…
Doch nun zum Nutzen von Sequenzen. Wirklich praktisch werden Sequenzen, wenn ihr eine Art “Schlüssel” über mehrere Tabellen definieren müsst. Um das zu demonstrieren, legen wir uns eine Sequenz und zwei Tabellen an, die diese Sequenz als Standardwert für ihre Id-Spalten verwenden:
DROP SEQUENCE IF EXISTS Test.SeqSharedKey; CREATE SEQUENCE Test.SeqSharedKey START WITH 1 INCREMENT BY 1; DROP TABLE IF EXISTS Test.SucceededRuns DROP TABLE IF EXISTS Test.FailedRuns CREATE TABLE Test.SuccededRuns ( RunId int NOT NULL DEFAULT (NEXT VALUE FOR Test.SeqSharedKey) ,RunName varchar(250) ) CREATE TABLE Test.FailedRuns ( RunId int NOT NULL DEFAULT (NEXT VALUE FOR Test.SeqSharedKey) ,RunName varchar(250) )
Nun fügen wir Zeilen ein und fragen die Tabellen ab:
INSERT INTO Test.SuccededRuns (RunName) VALUES ('First Succeeded'), ('Second Succeeded') INSERT INTO Test.FailedRuns (RunName) VALUES ('First Failed') INSERT INTO Test.SuccededRuns (RunName) VALUES ('Third Succeeded') SELECT RunId ,RunName FROM Test.SuccededRuns SELECT RunId ,RunName FROM Test.FailedRuns
Wir sehen, dass in Test.SucceededRuns
die Runs mit den RunIds 1, 2 und 4 zu finden sind, während der Eintrag mit der RunId
3 in Test.FailedRuns
eingetragen wurde.
Wichtig zu beachten ist dabei, dass hier aber keine Konsistenz gewährleistet ist, da es sich bei der RunId-Spalte nicht um eine Identity-Spalte handelt, könnten wir hier beliebige Werte eintragen, auch Duplikate oder Fantasiewerte. Anders als bei einer Spalte mit IDENTITY
-Eigenschaft würdet ihr das nicht einmal merken, da ihr nicht gezwungen seid, einen expliziten IDENTITY_INSERT
durchzuführen, sondern einfach in die Spalte schreiben könnt und anders als bei einer IDENTITY
-Spalte würde die Sequenz auch nicht “merken” dass hier schon ein höherer Wert eingetragen ist und dort fortsetzen sondern einfach stur beim nächsten Wert der Sequenz fortfahren. In solchen Fällen wäre also über die Applikation eine Sachgemäße Verwendung zu garantieren, da das Datenbanksystem sie nicht unbedingt garantieren kann.