# Inserts in 2 Tabellen 1:n



## heidiweber (1. Nov 2008)

Hallo,

derzeit erstelle ich mit Swing eine kleine Applikation, die über ein Formular Daten in eine Datenbank einträgt.
Die Eingaben auf dem Formular sollen in 2 Tabellen eingefügt werden.
Die beiden Tabellen haben eine 1:n Beziehung. Die Datenbank ist eine Oracle 11.

Wie man einen Insert macht, ist kein Problem. Nur wie man Daten in 2 Tabellen einfügt, überfordert mich.

Dies ist der beispielhafte Aufbau der beiden Tabellen:

Tabelle1:
ID (Autowert/Sequenz -> wird von Oracle automatisch vergeben)
Vorname
Nachname


Tabelle2:
IdRef (ID der Tabelle 1)
Menge
Artikel


Ich möchte jetzt einen Datensatz in Tabelle1 inserten und mehrere (vielleicht so ca. 50 Datensätze) in Tabelle 2 inserten.

1) Kann man dies mit einem Insert-Statement realisieren? Oder sollte man sowas nicht machen, falls dies überhaupt gehen sollte.

2) Mein Problem ist, dass ich ja in Tabelle 2 die ID der Tabelle2 als Fremdschlüssel benötige. 
Deswegen würde ich das so machen:
Insert in Tabelle1
Select max(ID) from Tabelle1 --> somit habe ich gerade eben vergebene ID
Und jetzt alle Inserts in Tabelle2 -> Entweder über "Insert ALL" oder über eine Schleife.

Das Mini-Problem, das ich hier sehe, ist, das in dem Moment, wo ich den Select max(ID) mache, gerade eben ein anderer Insert in Tabelle1 gemacht wurde und ich somit die falsche ID erhalte. Auch wenn dies sehr unwahrscheinlich sein sollte - könnte aber passieren. Sollte man daher lieber die Tabelle sperren?

Oder wie macht man sowas? 
Kann mir bitte jemand einen Tipp geben
Vielen Dank und einen schönen Feiertag
Grüße
Heidi


----------



## Sergeant_Pepper (1. Nov 2008)

Hallo Heide,

1) ob du mehrere insert-Statements benötigst, hängt von deiner Anwendung ab. Die Syntax von Oracle sieht das offenbar vor (siehe www.psoug.org/reference/insert.html)



> in dem Moment, wo ich den Select max(ID) mache, gerade eben ein anderer Insert in Tabelle1 gemacht wurde und ich somit die falsche ID erhalte.



2) ich würde eine Sequenz verwenden, um das Problem zu umgehen. Siehe www.psoug.org/reference/sequences.html


----------



## heidiweber (1. Nov 2008)

> 2) ich würde eine Sequenz verwenden, um das Problem zu umgehen. Siehe www.psoug.org/reference/sequences.html



Genau das ist doch mein Problem. Ich nehme doch in Tabelle1 eine Sequenz und es könnte eben zu diesem Problem kommen:



> Das Mini-Problem, das ich hier sehe, ist, das in dem Moment, wo ich den Select max(ID) mache, gerade eben ein anderer Insert in Tabelle1 gemacht wurde und ich somit die falsche ID erhalte. Auch wenn dies sehr unwahrscheinlich sein sollte - könnte aber passieren. Sollte man daher lieber die Tabelle sperren?



Deswegen meine Frage, wie ich das Problem lösen könnte?

Vielen Dank
Grüße
Heidi


----------



## Sergeant_Pepper (1. Nov 2008)

Die Antwort bleibt die gleiche: benutze eine Oracle-Sequenz (nicht etwas selbstgebautes).

Eine Oracle-Sequenz liefert exakt die Funktionalität, die du brauchst.

So wird eine Sequenz erzeugt (*einmalig* beim Anlegen der Datenbank):

```
create sequence id_kunde_seq increment by 1 start with 1
```
Den Startwert kannst du beliebig setzen.

So wird in einer Session der nächste freie Wert abgerufen:

```
id_kunde_seq.nextval
```

So wird in einer Session mit dem aktuellen Wert gearbeitet:

```
id_kunde_seq.currval
```

*Wichtig: *mehrere Aufrufe von id_kunde_seq.nextval liefern immer neue IDs. Du darfst also nextval nur aufrufen, wenn du tatsächlich eine neue (weitere) ID brauchst.

Wenn mehrere Sessions zeitgleich aktiv sind (das was du *völlig zu recht *befürchtest), bekommt jede Session durch nextval eine eindeutige ID. Genau das, was du willst.

Deine Inserts könnten so aussehen:

```
insert into tabelle1(id_kunde, vorname, nachname) values(id_kunde_seq.nextval, 'Billy', 'Joel') 
insert into tabelle2(id_kunde, menge, artikel)    values(id_kunde_seq.currval, 3, 'Klavier')
```
*Beachte die Verwendung von nextval und currval.*

Edit:
Zeile 2 wird bei dir wahrscheinlich _n_-mal mit anderen Werten für 'Menge' und 'Artikel' aufgerufen. Aber du musst bei jedem Aufruf 'id_kunde_seq.currval' verwenden.
Erst wenn du einen weiteren Kunden einträgst, benutzt du wieder 'id_kunde_seq.nextval'.

Ein ganz kleiner Nachteil: wenn mit nextval eine ID erzeugt wird, die dann - aus welchen Gründen auch immer - nicht verwendet wird, entstehen Lücken in der Abfolge der IDs. Aber das ist zweitrangig. Wichtig ist die Eindeutigkeit.

Wenn du keine Lücken willst, musst du dir die entsprechende Programmlogik selber ausdenken.


----------



## heidiweber (1. Nov 2008)

Hallo Sergeant Pepper,

genau dies habe ich auch nach mehrstündigem Testen gerade eben auch herausgefunden. Du bestätigst mir nur mein Tetsen Absolut spitze! Zerbeche mir schon seit Tagen den Kopf, wie ich das Problem lösen könnte - und jetzt macht das die Datenbank für mich. Oracle ist schon net schlecht Oder macht das (fast) jede Datenbank (DB2, MySQL, SQLServer....)? 

Dies sollte man in die FAQ aufnehmen. Habe ich bisher noch nirgends gefunden. Sollte eigentlich DB Grundwissen sein... 

Vielen Dank nochmals für die ausführliche Info.
Wünche dir noch ein schönes WE

Liebe Grüße
Heidi


----------



## maki (1. Nov 2008)

>> Oder macht das (fast) jede Datenbank (DB2, MySQL, SQLServer....)? 

Die anderen DBs geneerien eine ID beim einfügen des Datensatzes welche man abfragen kann.

Die "Lösung" mit der höchsten ID wird leider so schnell nicht aussterben, da genug Anfänger sich nicht so viele Gedanken machen wie du.


----------



## Sergeant_Pepper (1. Nov 2008)

Dir auch ein schönes Wochenende, und maki natürlich auch


----------

