IDENTITY-Poblem (SQL Server 2016)
-
Muss die fortlaufende Nummerierung sofort gesetzt werden, oder reicht es wenn es zu einem Zeitpunkt X durchgeführt wird?
Dann würde ich eine weitere nummerische Spalte die Null enthalten kann anlegen, und einen SELECT oder eine STP schreiben die alle Datensätze bei denen die Spalte NULL ist mit dem jeweiligen Maximum + 1 füllt.
-
@Benni07
Naja...
Sagen wir so ... es kommt drauf an wie man es betrachtet.Dinge wie Belege sind komplexe Objekte die aus mehreren Einzelteilen zusammengesetzt sind. Beim Anlegen kann daher an verschiedenen Stellen 'was schief gehen. (Du kannst nen Beleg nicht mit einem einzigen INSERT anlegen, der hat ja vermutlich noch Belegzeilen usw.)
Dann muss man zurückrollen. Um sicherzustellen dass dabei keine Löcher durch das Freiwerden der bereits "vergebenen" Nummer entstehen, muss man die ganze Transaktion in der so ein Beleg angelegt wird (und die Nummer vergeben) mit Isolation Level "serializable" machen. Weil ja sonst eine zweite Transaktion gleichzeitig laufen könnte, in der dann die nächste Nummer vergeben wird. Und wenn das erlaubt ist, und die 1. Transaktion abbricht, dann entsteht eben das verbotene Loch. *Das, also die Transaktion "serializable" machen, will man meistens nicht. Weil es praktisch verhindert dass Transaktionen gleichzeitig laufen können. Bzw. gibt es sogar DBs die es nichmal können.
Also muss man irgendwie rumtricksen. z.B. so wie es asc vorgeschlagen hat. Nur damit erlaubt man dann Belege die erstmal gar keine Nummer haben. Wobei man damit vermutlich noch leben kann. Man müsste halt definieren dass ein Beleg der keine Nummer hat einfach nicht existiert.
-
asc schrieb:
Muss die fortlaufende Nummerierung sofort gesetzt werden, oder reicht es wenn es zu einem Zeitpunkt X durchgeführt wird?
Dann würde ich eine weitere nummerische Spalte die Null enthalten kann anlegen, und einen SELECT oder eine STP schreiben die alle Datensätze bei denen die Spalte NULL ist mit dem jeweiligen Maximum + 1 füllt.
Die fortlaufende Nummerierung soll unmittelbar bei der Erfassung eines neuen Dokuments erfolgen. Pro Werktag sind das zurzeit zwischen 2 bis max. 25 Einträge.
-
Benni07 schrieb:
Pro Werktag sind das zurzeit zwischen 2 bis max. 25 Einträge.
Das ist super überschaubar wenig. Dafür reicht es wenn du das Gesamte Anlegen des Belegs/... in eine Transaktion packst, die Nummer per "MAX(Spalte) + 1" vergibst und einen Unique-Index auf die Spalte setzt. Wenn du dabei als Isolation-Level zumindest "READ COMMITTED" verwendest (und mindestens das ist glaube ich bei jedem RDBMS Standard) können so nie Löcher entstehen.
Was maximal passieren kann, ist dass das Anlegen eines Belegs schief geht. Wenn zwei solche Vorgänge gleichzeitig ausgeführt werden. Bei "READ COMMITTED" würden dann beide Versuchen die selbe Nummer für den neuen Beleg zu vergeben, aber dank des Unique Index auf die Spalte lässt das DBMS das nicht zu, und wirft dir eine der beiden Transaktionen mit nem Fehler zurück. Und dann machst du halt nen Retry.
-
Endlich mal was Brauchbares. Das probiere ich am Wochenende mal aus.
Danke schön!
hustbaer schrieb:
Benni07 schrieb:
Pro Werktag sind das zurzeit zwischen 2 bis max. 25 Einträge.
Das ist super überschaubar wenig. Dafür reicht es wenn du das Gesamte Anlegen des Belegs/... in eine Transaktion packst, die Nummer per "MAX(Spalte) + 1" vergibst und einen Unique-Index auf die Spalte setzt. Wenn du dabei als Isolation-Level zumindest "READ COMMITTED" verwendest (und mindestens das ist glaube ich bei jedem RDBMS Standard) können so nie Löcher entstehen.
Was maximal passieren kann, ist dass das Anlegen eines Belegs schief geht. Wenn zwei solche Vorgänge gleichzeitig ausgeführt werden. Bei "READ COMMITTED" würden dann beide Versuchen die selbe Nummer für den neuen Beleg zu vergeben, aber dank des Unique Index auf die Spalte lässt das DBMS das nicht zu, und wirft dir eine der beiden Transaktionen mit nem Fehler zurück. Und dann machst du halt nen Retry.
-
Alter Schwede, ich muss wohl besser auf Gross-/Kleinschreibung aufpassen.
-
Sind vlt. Trigger im Spiel?
Unabhängig davon muss die BelegNr NICHT lückenlos sein. Die Stelle möchte ich sehen wo das steht. Da eine BelegNr auch gerne alphanumerisch sein darf, hat sich das mit "Lücken" bereits erledigt. Im Volksmund spricht man von "fortlaufend", soll heißen eindeutig. Kannst auch ne GUID nehmen, nur will die niemand auf dem Bildschirm sehen.
-
"Fortlaufend" würde für mich auch mindestens noch implizieren dass spätere Rechnungen ne "höhere" Nummer haben (was ja auch bei Aplhanumerischen "Nummern" geht). Dann gingen GUIDs nicht.
Zur eigentlichen Frage, nämlich ob die Nummern "lückenlos" sein müssen, kann ich aber auch nur Texte finden wo steht dass dies nicht erforderlich ist.
-
Benni07 schrieb:
Endlich mal was Brauchbares. Das probiere ich am Wochenende mal aus.
Ist es das wirklich und in jedem Fall?
Nehmen wir einmal folgendes an (im Fall von Read Commited):
Benutzer A beginnt Transaktion und Schreibt Beleg(e)
Benutzer B beginnt Transaktion und Schreibt Beleg(e)
Benutzer A [in Transaktion] ermittelt MAX(Belegnummer)
Benutzer B [in Transaktion] ermittelt MAX(Belegnummer)
Beide nutzer commiten...Entweder: bei Benutzer B gibt es einen Schreibfehler (Eindeutigkeitsverletzung, sofern in DB entsprechend gesetzt) oder du hast 2x die gleiche Belegnummer.
Mit ersten kann man sicherlich leben, stollte den Fehlerfall aber zumindest im Hinterkopf halten.
-
Hab ich doch geschrieben. Also dass er nen Unique-Index braucht und dass dabei dann bei gleichzeitigem Eintragen das Anlegen von Belegen schief gehen kann.
Und ich bin sicher nicht beleidigt wenn du nen besseren Vorschlag hast (und Benny vermutlich auch nicht)
-
hustbaer schrieb:
Hab ich doch geschrieben. Also dass er nen Unique-Index braucht...
Sorry, überlesen
Ganz davon abgesehen das ich auch nichts gefunden habe was eindeutig belegen würde das Belegnummern lückenlos sein müssen.
-
Ja. Meiner Meinung nach wäre es auch die bessere Lösung hier etwas nachzuforschen, draufzukommen dass es das Problem eigentlich gar nicht gibt, und dann einfach nix zu machen.