Anmelden

View Full Version : Freie Nummer per Sql



tarkusch
25-07-13, 09:50
Hallo Kollegen,

falls ein neuer Artikel angelegt wird muss ich eine freie Nummer in der Datei ermitteln

Bisher habe ich die nächste freie Nummer im Artikelstamm per Schleife und Setll gesucht.


For I = 1 to 99999;
setll I FILE;
if Not %equal(FILE);
// Freie Kundennummer
ARTIKEL = I;
WRITE FILE;
LeaveSr;
ENDIF;
EndFor;

Kann ich das per Sql auch eleganter ermitteln?

Gruß

Tarki

andreaspr@aon.at
25-07-13, 10:16
Ich fürchte eine elegantere lösung wirst du auch nicht in SQL bekommen.

Ich selbst verwende wenn möglich "GENERATED ALWAYS AS IDENTITY (CYCLE)" für solche Spalten beim Erstellen einer Tabelle.
Dadurch benötige ich die ganze Verwaltung mit dem Nummerkreis nicht.

Beispiel
Tabelle TAB1 hat 3 Spalten:
ID
SP1
SP2

Beim Insert mache ich dann folgendes:

Select ID From Final Table
(Insert Into TAB1 (SP1, SP2)
Values ('Wert1', 'Wert2'))

Somit habe ich einen Satz hinzugefügt und bekomme als Ergebnis die neue Nr.

lg Andreas

Fuerchau
25-07-13, 10:40
Solange man die neuen SQL-Funktionen auch hat kann man sowas verwenden.
Bei sog. Altsystem/-lasten geht sowas halt nicht.

Ich habe mir für so einen Fall eine einfache Key-Datei generiert, die als Schlüssel alle Werte von 1-N enthält.

Select Key from Keyfile
where not exists (select * from Myfile where Key = MyFile.Key)
fetch first 1 rows only

erhalte ich dann die erste freie Nummer.
Über Performance darf man dann nicht reden:).

Aber es ist schon ungewöhnlich eine Nummernverwaltung auf diesem Wege durchzuführen. Normalerweise verwendet man ja Tabellen für so was.

B.Hauser
25-07-13, 10:45
Na ja, so was kann man schon mit SQL (und Rekursiven Abfragen und Exception Joins) hinbekommen.

Etwa so: Hier werden die Lücken zwischen Kunden-Nr. 10000 und 11000 ermittelt

With LfdNbr (Level)
as ( Values(10000)
Union All
Select Level + 1 from LfdNbr
Where Level < 11000)
Select x.*
from LfdNbr
exception join KundenStamm on Level = KundeNr

@Andreas

Wenn Du nur einen einzigen Satz einfügen willst, bringt Dir übrigens die Funktion IDENTITY_VAL_LOCAL die eingefügte Identity-Nr. zurück.

Birgitta

Fuerchau
25-07-13, 11:14
Mit V5R4 geht das leider wieder mal nicht.

B.Hauser
25-07-13, 11:23
Mit V5R4 geht das leider wieder mal nicht.

Sehr wohl!!!

Du musst nur den Values durch einen simplen SELECT ersetzten!


With LfdNbr (Level)
as ( Select 10000 from SysIbm/SysDummy1
Union All
Select Level + 1 from LfdNbr
Where Level < 11000)
Select x.*
from LfdNbr
exception join KundenStamm on Level = KundeNr

Birgitta

tarkusch
25-07-13, 12:02
Danke vielmals für eure (Nach)Hilfe.

Grüße

Tarki

BenderD
25-07-13, 12:07
... vernünftigen Durchsatz hat da ja wohl nur die IDENTITY Variante. Die B&B Varianten scheitern zudem entweder an fehlender Transaktionssicherheit oder an Sperren. Ohne ausreichendes Commit-Level gibt es da Doubletten und mit ausreichendem Commit-Level Dateiweite Sperren.
Wenn lückenlose Vergabe gefordert wird (oder später gefordert werden könnte) geht die Identity Variante auch nur ohne Transaktionssicherheit, ein Grund, warum ich da immer einen funtionalen getter mit einer zentralen Tabelle für Key-Verwaltungen vorziehe; das ist am flexibelsten und hat bei optimaler Implementierung den besten Durchsatz.

D*B