Einzelnen Beitrag anzeigen

Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#11

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

  Alt 5. Jul 2010, 17:42
@shmia:
Das ist nicht das Problem. Mit count will ich ja nicht den Wert ermitteln um den neuen Primärschlüssel (ID) zu erzeugen, sondern nur, ob der Datensatz (mit meiner ID) schon vorhanden ist, oder nicht. Zur Erzeugung der ID nutze ich natürlich eine Sequence (was in Oracle wohl dasselbe ist wie ein Generator bei firebird). Und diese wird hier per Trigger (auf before Insert) zugeführt.

@himi: Ja, man kann die Tabelle sperren. Finde ich aber nicht als geeignetes Mittel für so eine kurze Sache.


Ich machs jetzt Mal an einem meiner zahlreichen konkreten Umsetzungen ausführlich

1. Tabelle
SQL-Code:
CREATE TABLE "DBT_ZEIT"
   (   "ID_ZEIT" NUMBER NOT NULL ENABLE,
   "DATUM" DATE NOT NULL ENABLE,
   "STUNDE" NUMBER(2,0) NOT NULL ENABLE,
    CONSTRAINT "DBT_ZEIT_PK" PRIMARY KEY ("ID_ZEIT") ENABLE,
    CONSTRAINT "DBT_ZEIT_UK1" UNIQUE ("DATUM", "STUNDE") ENABLE
   ) ;
2. Sequence und Trigger
SQL-Code:
CREATE SEQUENCE "SEQ_ZEIT"  MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE ;

CREATE OR REPLACE TRIGGER "TRG_ZEIT"
BEFORE INSERT ON DBT_ZEIT
FOR EACH ROW
BEGIN
 SELECT SEQ_Zeit.NEXTVAL INTO :NEW.ID_Zeit FROM DUAL;
END;
Soweit alles ok. Die Sequence und Trigger entsprechen, wie gesagt, dem AutoInc bei mySQL. Erzeugt werden die beiden Sachen beim SQL Developer automatisch mit der Tabellenerzeugung, wenn man in dem Wizard entsprechend die Angaben setzt.

Jetzt kommt die SP mit besagtem unschönen Code:
SQL-Code:
create or replace
PROCEDURE "ADDTRAFFIC"
(aZeit in Date,
 aSrcIP in VarChar2,
 aDestIP in VarChar2,
 aTraffic in Number
) is
nTraffic64 Number(10) := 0;
nDatum Date;
nStunde Number(2);
id Number;
cnt Integer;
begin
  if aTraffic<64 then
    nTraffic64:=64-aTraffic;
  end if;
  
  nDatum:=trunc(aZeit);
  nStunde:=Extract(Hour from to_timestamp(aZeit));
  
    
  -- ****** Hier beginnt der Problembereich ******************************
  select count(id_zeit) into cnt from dbt_Zeit where
        Datum=nDatum and
        Stunde=nStunde;
  if cnt=0 then
    begin
      insert into dbt_Zeit (Datum,Stunde)
        Values (nDatum,nStunde)
        returning ID_Zeit into id;
    exception
      when dup_val_on_index then
        cnt:=1;
      when others then
        raise;
    end;
  end if;
  if cnt>0 then
    select id_zeit into id from dbt_Zeit where
        Datum=nDatum and
        Stunde=nStunde;
  end if;
  -- *** Ende des Problembreiches *************************************
  
  --commit;
  
  
  -- Für einen Insert or update gibt es folgenden Konstrukt:
  merge into dbt_Traffic
    using
      (Select count(Traffic) as cnt from dbt_Traffic
       where ID_Zeit=id
       and (SrcIP=aSRCIP or (SrcIP is null and aSRCIP is null ))
       and (DestIP=aDestIP or (DestIP is null and aDestIP is null))) e
    on (e.cnt>0)
  WHEN MATCHED THEN
    update set
        Traffic=Traffic+aTraffic,
        Traffic64=Traffic64+nTraffic64,
        Count_=Count_+1
        where ID_Zeit=id
        and (SrcIP=aSRCIP or (SrcIP is null and aSRCIP is null ))
        and (DestIP=aDestIP or (DestIP is null and aDestIP is null))
  WHEN NOT MATCHED THEN
    insert (ID_Zeit,SRCIP,DestIP,Traffic,Traffic64)
      Values(id,aSrcIP,aDestIP,aTraffic,nTraffic64);
  
  
  
  
  dbms_alert.signal('NewTraffic',to_char(nDatum,'dd.mm.yyyy') || ' ' ||
    to_char(nStunde) || ' ' ||
    aSRCIP || ' ' ||
    aDestIP || ' ' ||
    aTraffic || ' ' ||
    nTraffic64 || ' ' ||
    '1');
  
  commit;
 
end;
Also mich interessiert der Block ab "Select count(ID_Zeit) ..." (Problembereich). Kann man den in einen einzigen Befehl fassen (und ohne Exceptions nutzen).

@Borwin (roter Kasten)
Das ist das, was ich derzeit mache (nur von der anderen Seite aus). Nur ich hätte es gern ohne Exceptions gelöst (also ohne, dass ich mich bewusst auf eine Exception verlasse, denn das ist nach meinem Wissen nicht der Sinn einer Exception=Ausnahme). In deinem Beispiel würde noch eine Exception beim Insert geworfen, die du abfangen müsstest, wenn zwischenzeitlich ein anderer User den Eintrag gemacht hat.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat