# Freie ID in Tabelle ermitteln



## foobar (11. Aug 2008)

Hi,

wie kann man am einfachsten in einer Tabelle eine nicht verwendete ID ermitteln? Das ganze dient dazu dem Benutzer die Möglichkeit zu geben, die verwendete ID selbst zu bestimmen z.b. eine neue ID > 500.

Bisher habe ich nur sowas zu Stande gebracht:


```
select a.kdnr+1 
from rechkd a
where a.kdnr+1 not in (select b.kdnr
                       from rechkd b
                       where a.kdnr+1 = b.kdnr)
order by 1
```

Das funktioniert zwar ist aber nicht besonders performant. Geht das nicht einfacher?

Viele Grüße,
foobar


----------



## SlaterB (11. Aug 2008)

reicht nicht schon
where a.kdnr+1 not in (select b.kdnr from rechkd b )
?
dann muss die Subquery nur einmal berechnet werden,

aber kann wieder langsam sein, wenn die DB das 'in' nicht gut prüft und die Liste lang ist,

-------------
dann noch ein Left Join mit sich selbst und der Bedingung kndr+1?
wenn null, dann Wert nicht vorhanden


----------



## foobar (11. Aug 2008)

Stimmt die Wehreklausel ist obsolet:


```
select min(a.kdnr+1)
from rechkd a
where a.kdnr+1 not in (select b.kdnr
                       from rechkd b)
and a.kdnr+1 > 100                       
order by 1
```

Das liefert mir die kleinste freie ID größer als 100. 

Danke SlaterB


----------



## maki (11. Aug 2008)

Das hängt ganz stark von der DB ab, zuverlässig weiss ich dass es mit Oracle möglich ist.

Bei den hier vorgestellten Lösungen sollte man tunlichst darauf achten dass nicht ein anderer Thread zwischen der Abfrage und dem anlegen noch einen Datensatz ablegt.


----------



## foobar (12. Aug 2008)

Ja, das Verfahren ist nicht ganz unproblematisch. Man muß eben einfach vor dem eigentlichen Insert nochmals prüfen, ob die Id noch vorhanden ist, weil zwischen dem Berechnen der ID und dem eigentlichen Anlegen des Datensatzes jede Menge Zeit verstreichen kann.
Mit einem Left-Selfjoin habe ich das Problem bisher nicht lösen können. Ist es eigentlich Möglich jede Subselectquery auch mit einem Join abzubilden? Gibt es dazu eine Regel? Ich habe das mal so gelernt, aber eine Regel, die das beweist, ist mir nicht bekannt.


----------



## Sergeant_Pepper (12. Aug 2008)

Hallo,

bei Oracle fallen mir zwei Möglichkeiten ein:

1. eine Sequenz
oder
2. select max(id)+1 as neuer_index from tabelle

Bei der max-Abfrage gibt es aber wieder das Problem konkurrierender Zugriffe.
Die Sequenz hingegegen ist sicher.


----------



## foobar (13. Aug 2008)

max(id)+1 liefert aber nicht das gewünschte Ergebnis. Der benutzer kann sich aussuchen, ob er eine freie, möglichste kleine Id oder max(id(+1) oder eine Id seiner Wahl verwenden möchte.

Sequenzen gibt es bei Informix leider nicht :-(


----------



## SlaterB (13. Aug 2008)

Sequenzen würden auch nicht helfen, Lücken in der Id-Liste zu finden, 
sondern liefern nur immer quasi max(id)+1 auf performant einfache Weise,
ohne gelöschte rauszurechnen, ein einfacher Zähler,

wenn man parallel manuell Ids vergibt, dann kann auch eine Sequenz-Id zu einem Fehler führen


----------



## Sergeant_Pepper (13. Aug 2008)

SlaterB hat gesagt.:
			
		

> Sequenzen würden auch nicht helfen, Lücken in der Id-Liste zu finden,
> sondern liefern nur immer quasi max(id)+1 auf performant einfache Weise,
> ohne gelöschte rauszurechnen, ein einfacher Zähler,


Wenn die ID ausschließlich DB-intern Bedeutung hat, sind Lücken nicht schlimm.



> wenn man parallel manuell Ids vergibt, dann kann auch eine Sequenz-Id zu einem Fehler führen


Klar, das ist "tödlich". Man muss als Entwickler auf jeden Fall entscheiden, ob man einen Einfluss des Endanwenders auf die ID-Vergabe zulässt oder nicht. Wenn ersteres der Fall ist, sind mehr oder wenige aufwändige Prüfungen inkl. GUI-Feedback zu realisieren.

Wenn man programmintern *konsequent* mit Sequenzen (Oracle) oder Auto-Increments arbeitet, hat man keine Probleme, die durch parallele Sessions entstehen können.


----------

