# Fortlaufende Nummer - Was tun bei löschen?



## Basti14 (18. Mai 2014)

Hallo Leute, ich habe eine Frage, wie man folgendes Problem am besten bzw. professionellsten lösen könnte:

Also ich habe eine Tabelle die Mitarbeiter speichert (Fortlaufende Nr. als PrimaryKey, Vorname, Nachname). 

Jetzt möchte ich das hinzufügen und löschen eines Mitarbeiters implementieren. Angenommen es sind schon die Mitarbeiter von 1 - 10 drinnen, und ich lösche den 6. Mitarbeiter. Anschließend möchte ich einen neuen hinzufügen. 

Sollte der dann mit der Nr. 6 versehen werden? oder einfach weiter mit 11? Aber dann wäre ja eine Lücke vorhanden?

Aber wenn ich den Mitarbeiter 6 mit dem Namen "Herbert" lösche, obwohl ich ihn irgendwo anders im Programm verwendet habe und dann schreibe ich z.B. einen "Thomas" auf die Nr. 6 hinein, dann ist das ja ein logischer Fehler, weil eigentlich der Mitarbeiter "Herbert" gemeint wurde, aber da steht ja jetzt der "Thomas" drinnen?


Danke schonmal


----------



## turtle (18. Mai 2014)

> Aber wenn ich den Mitarbeiter 6 mit dem Namen "Herbert" lösche, obwohl ich ihn irgendwo anders im Programm verwendet habe


Das hört sich merkwürdig an. Abhängige Daten von Herbert sollten ebenfalls gelöscht werden, wenn Herbert "gelöscht" wird.

Weiterhin scheint mir das Datenmodell NICHT zu unterscheiden zwischen ID und fortlaufender Nummer.

Es sieht so aus, das deine Applikation auf "fortlaufende" Nummerierung Wert legt. Davon völlig unabhängig kann aber der primary key der Tabelle sein. Dann ist fortlaufende Nummer "nur" eine Spalte in der Tabelle.

Daher kannst du Herbert meiner Meinung nach sehr wohl die fortlaufende Nummer 6 geben, aber (natürlich) ist seine (primary key) ID bereits vergeben. Dein Code sollte unterscheiden zwischen Herberts ID bzw. dessen fortlaufender Nummer, denn es sind zwei verschiedene Dinge.

My 5 cents


----------



## Basti14 (18. Mai 2014)

Warum kann eine fortlaufende Nummer nicht auch gleichzeitig der PrimaryKey sein, der eine Zeile eindeutig identifiziert, da es diese ja nur 1x gibt?

Also wenn ich einen Mitarbeiter lösche, soll alles was mit diesem Mitarbeiter zu tun hat auch gelöscht werden oder wie?

Also wie sollte ich das jetzt am besten machen?


----------



## turtle (18. Mai 2014)

> Warum kann eine fortlaufende Nummer nicht auch gleichzeitig der PrimaryKey sein, der eine Zeile eindeutig identifiziert, da es diese ja nur 1x gibt?


Natürlich KANNST du eine Nummer, die neben der primary key-Eigenschaft noch eine weitere Business-Logik hat zum Primary key machen.

Aber dies ist nicht best-practice. 

So etwas wie deine fortlaufende Nummer hat ja offensichtlich neben der DB-Eindeutigkeit noch eine andere Bedeutung. Daher hast du ja auch Schwierigkeiten, einem Record eine neue fortlaufende Nummer zu geben. Daher mein Hinweis, das dies oft durch sogenannte Surrogate keys vermieden wird, indem ausschließlich ein Feld zur Identifikation des Record OHNE einen Bezug zur Business Logik eingefügt wird.



> Also wenn ich einen Mitarbeiter lösche, soll alles was mit diesem Mitarbeiter zu tun hat auch gelöscht werden oder wie?


Das ist Sache deines Mappings. Schau mal zu cascade Optionen. Da du nicht gesagt hast, wie du auf die DB zugreifst,...


> Also wie sollte ich das jetzt am besten machen?


Sagte ich bereits. Einen neuen primary key nehmen. Dann bist du frei mit deiner laufenden Nummer zu machen, was du für richtig hältst.


----------



## stg (18. Mai 2014)

Basti14 hat gesagt.:


> Also wenn ich einen Mitarbeiter lösche, soll alles was mit diesem Mitarbeiter zu tun hat auch gelöscht werden oder wie?



Das hängt ganz stark vom Anwendungsfall ab.
Herbert hat sicherlich einen Benutzeraccount für Computet o.Ä. am Arbeitsplatz. In der Datenbank weiß der Account nun, dass er zu Herbert gehört, aber einen entsprechenden Fremdschlüssel. Wird Herbert gefeuert, so ist der Benutzeraccound vermutlich auch sinnlos und der Datensatz würde ebenfalls aus der Datenbank gelöscht werden.
Hätte Herbert aber einen Firmenwagen, so hätte man in der Datenbank vermutlich eine ähnliche Verknüpfung, wie beim Useraccoutn. Nämlich der Firmenwagen merkt sich über einen Fremdschlüssel, zu wem er denn gehört. Wenn nun Herbert die Firma verlässt, dann bleibt der Wagen aber in der Regel im Besitz der Firma und der entsprechende Eintrag wird nicht aus der Datenbank gelöscht, sondern nur der Fremdschlüssel auf <NULL> gesetzt, was dann z.B. bedeutet, dass der Firmenwagen zur Zeit keinem Mitarbeiter zugewiesen wurde..


----------



## Tobse (18. Mai 2014)

stg hat gesagt.:


> Hätte Herbert aber einen Firmenwagen, so hätte man in der Datenbank vermutlich eine ähnliche Verknüpfung, wie beim Useraccoutn. Nämlich der Firmenwagen merkt sich über einen Fremdschlüssel, zu wem er denn gehört. Wenn nun Herbert die Firma verlässt, dann bleibt der Wagen aber in der Regel im Besitz der Firma und der entsprechende Eintrag wird nicht aus der Datenbank gelöscht, sondern nur der Fremdschlüssel auf <NULL> gesetzt, was dann z.B. bedeutet, dass der Firmenwagen zur Zeit keinem Mitarbeiter zugewiesen wurde..



Genau das ist das Problem. Kurzes Beispiel:

```
Tabelle Mitarbeiter
id (INT, AUTO_INCREMENT) | Name (VARCHAR)
-------------------------+--------
1                        | Hans
-------------------------+--------
2                        | Jürgen
-------------------------+--------
3                        | Franz
-------------------------+--------
4                        | Bruno

Tabelle Gehalt
Speichert alle GehaltsÄNDERUNGEN gegenüber dem "Standardgehalt"
montaslohn (FLAOT)   | mitarbeiter_id (INT) | gueltig_ab (DATE)
---------------------+----------------------+-------------------
1500                 | 1                    | 1.1.2000
---------------------+----------------------+-------------------
2000                 | 1                    | 1.1.2001           // Hans halt also am 1.1.2001 eine Gehaltserhöhung bekommen
---------------------+----------------------+-------------------
2300                 | 2                    | 1.1.2000
---------------------+----------------------+-------------------
2400                 | 3                    | 1.1.2002
---------------------+----------------------+-------------------
2800                 | 4                    | 1.2.2002
```

2003 wird Franz gekündigt und Reiner wird stadtdessen eingestellt. Reiner bekommt die ID 3 von Franz da die ID fortlaufend sein soll.


```
Tabelle Mitarbeiter
id (INT, AUTO_INCREMENT) | Name (VARCHAR)
-------------------------+--------
1                        | Hans
-------------------------+--------
2                        | Jürgen
-------------------------+--------
3                        | Reiner
-------------------------+--------
4                        | Bruno

Tabelle Gehalt
Speichert alle GehaltsÄNDERUNGEN
montaslohn (FLAOT)   | mitarbeiter_id (INT) | gueltig_ab (DATE)
---------------------+----------------------+-------------------
1500                 | 1                    | 1.1.2000
---------------------+----------------------+-------------------
2000                 | 1                    | 1.1.2001           // Hans halt also am 1.1.2001 eine Gehaltserhöhung bekommen
---------------------+----------------------+-------------------
2300                 | 2                    | 1.1.2000
---------------------+----------------------+-------------------
3200                 | 3                    | 1.1.2002
---------------------+----------------------+-------------------
2800                 | 4                    | 1.2.2002
```
Reiner wurde 2003 eingestellt, hat aber laut Datenbank 2002 (also *vor* der Einstellung) eine Gehaltserhöhung auf 3200 bekommen. Das macht keinen Sinn.

Dieses Beispiel sieht jetzt mal davon ab, dass es für ein echtes Unternehmen Sinn machen würde Franz bei einer Kündigung nur als gelöscht/gekündigt zu "markieren" und alle Daten über Ihn zu behalten. Wenn man jetzt aber nicht von Mitarbeitern Spricht sondern anderen Daten welche tatsächlich problemlos "entsorgt werden können" und das Script achtet beim Löschen nicht *pinibelst* darauf, dass alle Referenzierenden Datensätze gelöscht werden, kommt es zu *gravierenden* Inkonsistenzen (die im schlimmsten Fall das komplette System lahmlegen können).

Wenn du MySQL Benutzt kannst du mit der MyISAM-Engine angeben, zwischen Welchen Tabellen/Spalten welche Korrelation besteht. MyISAM löscht dann alle Datensätze wenn der Priamry-Satz gelöscht wird um genau solche Inkonsistenzen zu vermeiden. Das macht aber die Datenbank nur unnötig langsam und sich auf die Engine zu verlassen ist _alles andere_ als Best-Practice.

*Fazit:*
wenn eine fortlaufende Nummerierung notwendig ist musst du sie bei jedem hinzufügen/löschen eines Mitarbeiters neu erstellen. Diese fortlaufende Nummerierung darf aber *niemals* der Primary-Key sein da es sonst (wie oben erläutert) eklig wird.


----------



## Thallius (18. Mai 2014)

Ich würde niemals einen Benutzer aus einer Datenbank Tabelle werfen. Mache ein Status Feld in die Tabelle wo du den User auf inaktiv, gelöscht, gesperrt etc setzen kannst. 

Gruß

Claus


----------

