Einzelnen Beitrag anzeigen

Benutzerbild von IBExpert
IBExpert

Registriert seit: 15. Mär 2005
672 Beiträge
 
FreePascal / Lazarus
 
#45

AW: Wie eindeutige Rechnungsnummer in DB erstellen und speichern?

  Alt 7. Dez 2016, 10:29
Vielleicht mal wieder zurück zur ursprünglichen Frage: Wie kann man so was machen, wenn man es
aus welchen Gründen auch immer braucht (und ein sehr guter Grund ist das der Kunde dafür Geld
bezahlt)

Wir machen das so:

Es gibt eine Tabelle, in der werden z.B. 100 fortlaufende Nummern auf Vorrat eingetragen. Dafür
sorgt ein On Delete Trigger, der auf dieser Tabelle einfach zählt wie viele noch drin sind und zB
bei weniger als 50 Einträgen einfach wieder auf 100 auffüllt, die jeweils das Maximum um 1 erhöhen.
Die erzeugte Nr ist unique indiziert.

Sollte dieser Trigger von 2 Clients gleichzeitg aufgerufen werden, kommt es zu einer Exception und
durch eine "when any do begin end" Anweisung am Ende des Triggers wird diese Exception von einem der
beiden dann ignoriert, der andere wird dann aber dafür gesorgt haben, das ausreichend Vorrat existiert.

Abgerufen wird die Nummer über eine Prozedur, z.B. GETNR, diese liefert ein Result, varchar oder
Integer oder was auch immer.

Diese Prozedur wiederum nutzt eine 2. Prozedur Getnrx. In dieser wird
die kleinste Nummer abgerufen und mit dem delete gelöscht
NR ist ein RETURN Parameter dieser SP. N ist ein Input Parameter, der als Default 0 hat.

SQL-Code:
create procedure getnrx
(n integer=0)
returns
(nr varchar(20))
as
begin
  nr='';
  select first 1 nr skip (:n) from nrtbl order by nr into :nr;
  delete from nrtbl where nr=:nr;
  suspend;
  when any do begin nr=''; suspend; end;
end
Wenn es beim Aufruf nun zu einer exception kommt weil 2 Transaktionen zeitnah konkurrierend
die selbe Nummer löschen wollen, wird die SP beim zweiten kein Ergebnis liefern. In der
aufrufenden SP GETNR arbeiten wir daher so

SQL-Code:
create procedure getnr
returns
(nr varchar(20))
as
declare variable n integer
begin
  n=0;
  nr='';
  while (nr='') do
  begin
    select nr from getnrx(:n) into :nr;
    if (nr='') then n=n+1;
    if (n>100) then exception err 'irgendwas stimmt hier nicht';
  end
  suspend;
end
Wer nun auf Kundenwunsch auch gerne Nummern recyclen möchte, kann das problemlos machen, in dem er auf jeder Tabellen,
in der die Nummer benutzt wird, mit einem OnDelete Trigger diese wieder in die nrtbl einträgt, denn die werden dann
automatisch wieder benutzt. Die SP kann dabei ggf auch selber dafür sorgen, das die eingetragenen Nummern
noch den gewünschten Präfix haben, wie zB extract(year from current_date) usw. Falls da noch alte Nummern drin
sind, kann die GetNR SP diese selber löschen und neue für die aktuelle Periode anlegen usw.

Der o.a. code ist nicht getestet sondern enfach so runtergetippt, sollte aber den meisten weiterhelfen und
verdeutlicht viele hier schon geschilderte Ideen, ergänzt aber das interne zweistufige Exception Handling.

Das Verfahren nutzen wir in mehreren Projekten es es funktioniert konfliktfrei, so das sich der FrontEnd
darum keine Kopf machen muss. Wenn der eine Nummer braucht kann er die SP aufrufen oder noch besser lässt das
durch einen Insert Trigger auch die DB machen, damit das auch gespeichert ist und ggf durch den delete Trigger
wieder freigegen wird. Wer Lücken akzeptiert nimmmt einfach keine delete trigger oder holt sich das aus einem
Generator, den man mit einem execute statement 'set generator ....' auch jederzeit am monatsanfang resetten
kann.

Viele Weg führen zum Ziel aber geht nicht gibts nicht und als Softwaredienstleister dem Kunden seine etablierten
Prozessstrukturen auszureden ist ein sehr gefährliches Spiel. Wenn er die Nummer so haben will, why not ....

Wir arbeiten hier fast alle im ältesten Gewerbe der Welt: Wir machen Kunden für Geld glücklich .....
Holger Klemt
www.ibexpert.com - IBExpert GmbH
Oldenburger Str 233 - 26203 Wardenburg - Germany
IBExpert and Firebird Power Workshops jederzeit auch als Firmenschulung

Geändert von mkinzler ( 7. Dez 2016 um 10:53 Uhr) Grund: SQL-Tags eingefügt
  Mit Zitat antworten Zitat