Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   [PLSQL] Gibt es ein "Select oder Insert"- Befehl? (https://www.delphipraxis.net/152756-%5Bplsql%5D-gibt-es-ein-select-oder-insert-befehl.html)

sirius 5. Jul 2010 14:35

Datenbank: Oracle • Version: 11 • Zugriff über: verschiedenes

[PLSQL] Gibt es ein "Select oder Insert"- Befehl?
 
Wenn man einen Datensatz updaten möchte, aber nicht sicher ist, ob er bereits existiert kann man das Kommando "MERGE INTO" nutzen. Welches in einem Abwasch bspw. eine "Select count.."-Abfrage macht und dann entscheidet, ob ein Insert oder ein update notwendig ist.

Ich brauche dies aber des öftern für einen anderen Konstrukt. Ich möchte eine Entscheidung ob ich ein "Select ID ..." oder ein "Insert ... returning ID ..." brauche in einem Befehl (ID ist bei mir immer der PK) Da ich vermute, dass ich damit nicht der einzige bin (ich im Netz aber nichts finde; bei "Select oder Insert" findet man zu viel), würde ich gern mal wissen, ob es dafür etwas gibt.
Bisher löse ich das folgendermaßen:
SQL-Code:
Select count(ID) into c from ...

if c=0 then
  begin
    insert into dbt_Channel ...
      returning ID into result;  
    commit;
  exception
    when dup_val_on_index then
      c:=1; -- falls zwischenzeitlich ein zweiter User einen Datensatz eingefügt hat?!?
    when others then
      raise;
  end;
end if;

if c>0 then
  Select ID into result ...
end if;

return(result);

himitsu 5. Jul 2010 14:46

AW: [PLSQL] Gibt es ein "Select oder Insert"- Befehl?
 
Ob es bei PLSQL geht, weiß ich nicht, aber die SQL-Syntax kennt da ein "Insert or Update".

Es ist praktisch ein INSERT und falls es Probleme mit doppelten/vorhandenen Keys gibt, dann wird das UPDATE versucht.

SQL-Code:
INSERT INTO `table` ( 'field1', 'field2' ) VALUES ( 'value1', 'value2' )
ON DUPLICATE KEY UPDATE 'field2' = 'value2'
field1 ist hierbei z.B. ein Primary-/Unique-Key und deshalb hab ich ihn beim Update weggelassen, da er sich ja eh nicht ändert
und über diesen schon der zu ändernde Datensatz ausgewählt wurde.

mkinzler 5. Jul 2010 14:48

AW: [PLSQL] Gibt es ein "Select oder Insert"- Befehl?
 
Liefert dir MERGE die ID nicht zuück?

Unter FireBird könnte man
SQL-Code:
Update or insert ... matching ... returning ID;
verwenden

sirius 5. Jul 2010 14:56

AW: [PLSQL] Gibt es ein "Select oder Insert"- Befehl?
 
Oh Sorry,

ich sehe, ich habe die Frage falsch erklärt. Eine "insert-update" Variante gibt es (nennt sich "Merge Into"). Was ich suche ist eine "Select - Insert returning" Variante (wie im Codebesipiel als umständliche Langform gezeigt).

Schonmal Danke für Eure Bemühungen.

Edit: Wobei mir deine Syntax, himi, auch neu ist (schön wenn man mal redet, da lernt man immer was), ich sie aber hier nicht brauche.

HeZa 5. Jul 2010 15:29

AW: [PLSQL] Gibt es ein "Select oder Insert"- Befehl?
 
Irgendwie hast du mehr Code als nötig.

SQL-Code:
begin
  insert into dbt_Channel ...
    returning ID into result;  
  commit;
  return(result);
exception
  when dup_val_on_index then
    return ID; -- falls zwischenzeitlich ein zweiter User einen Datensatz eingefügt hat?!?
  when others then
    raise;
end;
[/QUOTE]

sirius 5. Jul 2010 15:36

AW: [PLSQL] Gibt es ein "Select oder Insert"- Befehl?
 
Hi HeZa,

jo, so kann man es auch machen. Es bestehen aber zwei Nachteile:
1. Exception, die man vorher abfangen kann sind doof (und normalerweise auch sehr performanceraubend, zumal in dem Fall bis auf den ersten Eintrag immer die Exception geworfen wird)
2. Da auf das Insert ein Trigger (inkl. sequence) angelegt ist, welcher die ID setzen soll (=AutoInc bei mySQL), läuft der auch hoch, obwohl das Insert schief gelaufen ist.

shmia 5. Jul 2010 16:30

AW: [PLSQL] Gibt es ein "Select oder Insert"- Befehl?
 
Das Grundproblem ist die ungeeignete Erzeugung des Wertes für den Primärschlüssel.
SQL-Code:
Select count(ID) into c from ...
Wehe es wird ein Datensatz gelöscht - dann gerät das ganze System durcheinander.
Besser ist da:
SQL-Code:
Select Max(ID)+1 into c from ...
Aber auch das ist nicht wasserdicht wenn mehr als ein Prozess/Thread das abarbeitet.
Was man hier wirklich bräuchte wäre ein Generator.
Dann würde man zuerst mit dem Generator eine "neue Nummer ziehen" und könnte dann sicher sein, dass es keine Kollisionen von anderen Prozessen gibt.

himitsu 5. Jul 2010 16:44

AW: [PLSQL] Gibt es ein "Select oder Insert"- Befehl?
 
Zitat:

Zitat von shmia (Beitrag 1033622)
und könnte dann sicher sein, dass es keine Kollisionen von anderen Prozessen gibt.

Kann man Tabellen nicht auch sperren?

Mschmidt 5. Jul 2010 17:28

AW: [PLSQL] Gibt es ein "Select oder Insert"- Befehl?
 
Zitat:

Zitat von himitsu (Beitrag 1033624)
Zitat:

Zitat von shmia (Beitrag 1033622)
und könnte dann sicher sein, dass es keine Kollisionen von anderen Prozessen gibt.

Kann man Tabellen nicht auch sperren?

jeap select ... for Update [nowait];

borwin 5. Jul 2010 17:30

AW: [PLSQL] Gibt es ein "Select oder Insert"- Befehl?
 
Hallo Sirius,

irgendwie passt das nicht zusammen wie Du es beschreibst.
Zitat:

"Select ID ..." oder ein "Insert ... returning ID ..."
Willst Du wissen ob es die ID schon gibt musst Du in der WHERE Bedingung die ID abfragen.

Da gibt es zwei Möglichkeiten um das zu prüfen.

SQL-Code:
begin
  select ID
  into result
  from tabelle
  where ID = übergabeparameter
exception
 when no_data_found then
   -- Neuen Datensatz einfügen
   insert into tabelle .....
end
anderer weg wäre

SQL-Code:
declare
 vlb_found boolean := false;
begin
for rec in (select * from tabelle where ID = parameter) loop
  vlb_found := true;
end loop;
 if not vlb_found then
   -- neuen Datensatz einfügen
   insert into tabelle .....
 end if;
end;
Die ID kommt hoffentlich aus einer Sequenz im Trigger? Sonst einbauen.

Gruß Borwin


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:34 Uhr.
Seite 1 von 3  1 23      

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