Delphi-PRAXiS
Seite 3 von 4     123 4      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Letzte vergebene Nummer speichern (https://www.delphipraxis.net/211150-letzte-vergebene-nummer-speichern.html)

Delphi.Narium 5. Aug 2022 18:25

AW: Letzte vergebene Nummer speichern
 
Für mich immernochnicht wirkliche Klar ist: Was ist die letzte ID?

Zuerst die SP aufgerufen, zuletzt die SP aufgerufen?

Zuerst in der SP (unabhängig von der Gesamtlaufzeit) erstellte ID?

Zuletzt in der SP (unabhängig von der Gesamtlaufzeit) erstellte ID?

Der höchste Wert, der, ohne Beachtung von Prefix und Suffix, ermittelt wurde?

Der Moment, in dem in der SP die ID feststeht, unabhängig von der Laufzeit der davor und der danach auszuführenden Teile der SP?

Post #8 und #12 geben mir da noch nicht ausreichend Klarheit.

Eventuell könnte man die Tabelle LastId noch etwas aufbohren:

SQL-Code:
create Table LastID
(
  Reihenfolge BIGINT not null,
  DeineID Integer not null, -- oder welcher Type das auch immer sein mag.
  Prefix VarChar(32), -- oder wie lang Präfix auch immer maximal lang sein mag
  ID Integer,
  Suffix VarChar(32) -- oder wie lang Suffix auch immer maximal lang sein mag
);
CREATE GENERATOR GEN_Reihenfolge;
SET GENERATOR GEN_Reihenfolge TO 0;

-- in der SP an geeigneter Stelle:
insert into LastID (Reihenfolge, DeineID, Prefix, ID, Suffix) values (Gen_ID(GEN_Reihenfolge, 1), DeineID, a, b, c);
Dann könnte die letzte ID z. B. sinngemäß in der Art ermittelt werden:
SQL-Code:
select ID from LastID
where Reihenfolge =
(
  select Max(Reihenfolge) as MaxID
  from LastID
  where Prefix = 'gesuchtes Präfix'
  and Suffix = 'gesuchtes Suffix'
)
Aber nach Deinem letzten Einwand dürfte sich das Problem auch nur örtlich, aber nicht zeitlich, verlagern.

Oder:
SQL-Code:
SP
begin
  insert into LastID (Reihenfolge, DeineID) values (Gen_ID(GEN_Reihenfolge, 1), ErzeugeMeineID);
end;
Inzwischen ahne ich, wo das konkrete Problem zu suchen ist und nein, eine wirkliche Lösung fällt mir dazu nicht ein :-(

BlueStarHH 5. Aug 2022 18:36

AW: Letzte vergebene Nummer speichern
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1509817)
Für mich immernochnicht wirkliche Klar ist: Was ist die letzte ID?

Der höchste Wert, der, ohne Beachtung von Prefix und Suffix, ermittelt wurde?

Fast richtig. Der letzte Wert, den *mein* Generator in meiner SP erzeugt hat. Das ist meistens der höchste Wert von meinem Generator aber nicht immer. Wenn der Generator wieder bei 1 anfägt.

Delphi.Narium 5. Aug 2022 18:43

AW: Letzte vergebene Nummer speichern
 
Ja, aber dann ist es immernoch der mit der höchsten Reihenfolge.
SQL-Code:
select ID from LastID
where Reihenfolge =
(
  select Max(Reihenfolge) as MaxID
  from LastID
  where Prefix = 'gesuchtes Präfix'
  and Suffix = 'gesuchtes Suffix'
)
müsste dann schon passen.

BlueStarHH 5. Aug 2022 18:46

AW: Letzte vergebene Nummer speichern
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1509819)
Ja, aber dann ist es immernoch der mit der höchsten Reihenfolge.

Nein. Siehe mein Beispiel in Post #20. Und der Generator kann ja wieder von 1 anfangen und dann im zweiten Durchlauf den ersten Durchlauf überholen. Oder im ersten Durchlauf generell einen höheren Wert erreicht haben als im zwweiten oder n-ten Durchlauf.

Uwe Raabe 5. Aug 2022 18:58

AW: Letzte vergebene Nummer speichern
 
Ich sehe da momentan drei Möglichkeiten für eine Kollision durch nebenläufigen Zugriff:
  1. Beide verwenden den Generator
  2. Einer verwendet den Generator, der andere nicht
  3. Beide verwenden den Generator
Punkt 1 ist offenbar unkritisch: Es ist egal, welche der erzeugten IDs wir speichern.
Punkt 2 habe ich so verstanden, dass dann die ID mit Generator gewinnt.
Punkt 3 wäre der Fall, wo der höhere Generatorwert gewinnt, wenn wir ausschließen können, dass während der Kollision der Generator zurückgesetzt wird.

Ist das soweit richtig?

BlueStarHH 5. Aug 2022 19:03

AW: Letzte vergebene Nummer speichern
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1509824)
Ich sehe da momentan drei Möglichkeiten für eine Kollision durch nebenläufigen Zugriff:
  1. Beide verwenden den Generator nicht
  2. Einer verwendet den Generator, der andere nicht
  3. Beide verwenden den Generator
Punkt 1 ist offenbar unkritisch: Es ist egal, welche der erzeugten IDs wir speichern.
Punkt 2 habe ich so verstanden, dass dann die ID mit Generator gewinnt.
Punkt 3 wäre der Fall, wo der höhere Generatorwert gewinnt, wenn wir ausschließen können, dass während der Kollision der Generator zurückgesetzt wird. Beim Zurücksetzen gewinnt der neue Startwert.

Ist das soweit richtig?

Ja, ich habs nochmal konkretisiert in fett.

Delphi.Narium 5. Aug 2022 19:08

AW: Letzte vergebene Nummer speichern
 
Wann wird denn der Generator auf 1 gesetzt?

Datumsabhängig? Dann muss das Datum, das Quartal, der wie auch immer geartete Wert, anhand dessen eine Zeitabfolge erkennbar werden könnte, mit in die Tabelle LastID.

Z. B. sowas in der Art?

SQL-Code:
insert into LastID (Reihenfolge, DeineID, Prefix, ID, Suffix, Monat, Jahr)
values (Gen_ID(GEN_Reihenfolge, 1), DeineID, a, b, c, Month(Current_Date), Year(Current_Date));
SQL-Code:
select Max(ID) as MaxID
from LastID
where Prefix = 'gesuchtes Präfix'
and Suffix = 'gesuchtes Suffix'
and Monat = 1
and Jahr = 2022
Letztlich muss die Information mitgespeichert werden, mit der eindeutig festgestellt werden kann, zu welchem Zeitraum die zu ermittelnde letzte ID gehört.

Uwe Raabe 5. Aug 2022 21:11

AW: Letzte vergebene Nummer speichern
 
Ich glaube, es fehlt ein Kriterium, mit dem man feststellen kann, ob zwischen zwei Generatorwerten ein Rücksetzen stattgefunden hat. Andernfalls gibt es keine Möglichkeit, die Werte im Nachgang zu priorisieren.

Man könnte z.B. beim Rücksetzen einen Zählerwert erhöhen. Damit wäre die Kombination Zählerwert/Generator-ID eindeutig.

Delphi.Narium 6. Aug 2022 18:34

AW: Letzte vergebene Nummer speichern
 
@BlueStarHH

Schau doch bitte mal, ob Du damit einen Ansatz bauen kannst: FireBird - Understanding the WITH LOCK clause
SQL-Code:
Syntax and behaviour

    SELECT ... FROM single_table
       [WHERE ...]
       [FOR UPDATE [OF ...]]
       [WITH LOCK]
Damit wird bis zum Commit eine Tabelle / ein Datensatz / eine Spalte gelockt. Andere können dann nicht schreiben, bekommen entweder eine Exception oder warten, bis die Freigabe erfolgt. Das kommt doch dann einer CriticalSection sehr nahe.

Dazu müsstest Du dann am Beginn der SP eine Tabelle / einen Datensatz / eine Spalte locken und zwar entsprechend für die Speicherung der jeweils letzten ID. Am Ende der SP schreibst Du dann die in der SP ermittelte ID entsprechend. Das anschließende Commit, egal aus ob aus der SP heraus oder aus dem aufrufenden Progamm, gibt den Datensatz bzw. Tabelle wieder frei, ebenso natürlich auch ein Rollback.

Für fachlich unterschiedliche IDs könnest Du dann eine Tabelle, mit nur einer Zeile, aber je ID einer Spalte, erstellen, per Select am Beginn der SP den Datensatz mit explizitem Lock auf die zu ändernde ID-Spalte lesen und am Ende genau die Spalte mit der ermittelten ID aktuallisieren.

Ohne auf korrekte Syntax zu achten als Idee:
SQL-Code:
procedure GetNextID
  SELECT LetzteIDSpalte FROM LetzteIDTabelle
  FOR UPDATE OF LetzteIDSpalte
  WITH LOCK;

  a := ErzeugePrefix;
 
  if Bedingung then
    b := gen_id(MeinGenerator, 1);
    UPDATE LetzteIDTabelle set LetzteIDSpalte = b;
  else
    b := '';

  c := ErzeugeSuffix;

  result := a+b+c;
end;

bnreimer42 6. Aug 2022 19:41

AW: Letzte vergebene Nummer speichern
 
Man kann in Firebird einen Generator als "Sperre" und zum Prüfen, ob Du loslegen darfst verwenden.

Z.B.
Generator mit 0 initialisieren (Irgendwann mal, wenn kein Programm läuft)

Im Programm (oder Stored Procedure)
Einfach wert des Generators erhöhen.
Wenn = 1 dann mache, was Du tun musst, kein anderer kommt Dir in die Quere
Wenn > 1 reduziere den Generator um 1 und brich ab.

Das läuft super, außer die Prozedur bricht ab, wenn der Generator auf 1 steht, denn dann bleibt die Sperre auf ewig. Muss dann vom Admin wieder auf 0 gesetzt werden, wenn kein Programm läuft.

Das Vorgehen ist einfacher, als in einer Tabelle mit LOCK einen Satz zu sperren.


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:50 Uhr.
Seite 3 von 4     123 4      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz