Zum Inhalt springen

innerhalb trigger wert aus tabellenspalte in variable schreiben?


pel

Empfohlene Beiträge

Hallo,

1.)Ich habe z.B. diesen Trigger:

anzahl ist eine Tabellenspalte. BestellPos ist die TAbelle

Aufgabenstellen: Nachdem Tupel gelöscht wird soll von diesem Tupel in der Spalte anzahl der Wert in die variable varanzahl geschrieben werden. Ist der code richtig so? bekomme keinen compile-error aber auch keine Ausgabe siehe unten...

CREATE OR REPLACE

TRIGGER TRIGGER1

After DELETE ON BESTELLPOS


declare varanzahl number;


BEGIN

dbms_output.enable;


select anzahl into varAnzahl from bestellpos;

dbms_output.put_line('anzahl: '|| varanzahl);


END;

2.)Ich suche das Ausgabefenster in dem sql developer oracle tool

wo die Ausgabe "varanzahl" stehen müsste finde aber nichts?

Handbuch, HIlfe , google halfen nicht weiter...

Link zu diesem Kommentar
Auf anderen Seiten teilen

Edit: sorry für neuen post, konnte nicht editieren?

3.) Wie kann ich werte aus Spalten auslesen dessen Zeile gelöscht wurde, ich aber nicht weiß welche Zeile gelöscht wurde? Dies steht ja erst zur Laufzeit fest...

Link zu diesem Kommentar
Auf anderen Seiten teilen

Nachdem Tupel gelöscht wird soll von diesem Tupel in der Spalte anzahl der Wert in die variable varanzahl

Wenn Du dir das durchließt - kommt dir das nicht seltsam vor? Nach der Löschung willst Du etwas aus der Tabelle selektieren? Wo nichts ist kann auch nichts werden um es mal so auszudrücken ;)

Dazu gibt es in Triggern die new und old Variablen, mit denen Du auf den alten und neuen Wert zugreifen kannst( wobei old bei einem einem Insertrigger sinnigerweise nicht vorhanden ist ebensoenig wie new bei einem delete trigger)

Allerdings funktioniert das nur, wenn du einen Rowlevel Trigger anlegst.

Dein Tigger muss also so aussehen:

CREATE OR REPLACE

TRIGGER TRIGGER1

After DELETE ON BESTELLPOS

[b]FOR EACH ROW[/b]

BEGIN


  dbms_output.put_line('anzahl: '||:old.anzahl);


END;

/

Handbuch, HIlfe , google halfen nicht weiter...

Das kann ich fast nicht glauben. Suchst du in der SQLDeveloper (Version 1.5) Hilfe nach dbms_ouptut, ist es der 3.Link (Using The SQL Worksheet)

Dort gibt es einen Reiter DBMS_OUTPUT (klingt auch logisch oder?) Jetzt musst nur doch die kleine Sprechblase drücken damit gepollt wird. Das Intervall kannst über den Schieberegler einstellen.

Dim

Bearbeitet von dr.dimitri
Link zu diesem Kommentar
Auf anderen Seiten teilen

super danke dir ich suchte immer nach output nicht dbms_output :D

kannst du mir sagen wie ich innerhalb dieses trigger nicht auf die tabelle Bestellpos sondern auf eine andere Tabelle bzw. deren Spalte Betrag in der DB zugreifen kann nennen wir sie: Rechnung z.B.

Declare my_rechnung Rechnung%ROWTYPE


Begin


my_rechnung.Betrag 
(würde das so stimmen) ?? obwohl ich nicht:
REFERENCING OLD AS old  FOR EACH ROW

ganz oben angab, funkioniert der Trigger vom 1.post, woher kommt das?

Bearbeitet von pel
Link zu diesem Kommentar
Auf anderen Seiten teilen

ganz oben angab, funkioniert der Trigger vom 1.post, woher kommt das?

Das sind Standardwerte. Zu sagen, dass man OLD als old ansprechen möchte ist relativ sinnfrei.

(würde das so stimmen) ??

Nein.

In einer Datenbank greifst Du auf Daten mittels SELECT zu. Sprich Du musst das was Du haben möchtest in eine Variable selektieren.

SELECT spalte INTO variablel FROM tabelle WHERE bedingung

Allerdings sollten Tigger sparsam benutzt werden und auch so wenig wie möglich fachliche Logik enthalten. Benutze sie nicht um irgendetwas zu "abstrahieren" oder ähnliches.

Dim

Link zu diesem Kommentar
Auf anderen Seiten teilen

CREATE OR REPLACE TRIGGER TRIGGER1 After Insert or Delete ON BESTELLPOS

FOR EACH ROW


Declare

my_anzahl number; 


BEGIN

  SELECT :old.anzahl INTO my_anzahl FROM bestellpos; 

  dbms_output.put_line('anzahl: '||my_anzahl);  

END;
Fehler:
DELETE FROM "PEL"."BESTELLPOS" WHERE ROWID = 'AAADZIAAEAAAAD9AAD' AND ORA_ROWSCN = '448030' and ( "POSNR" is null or "POSNR" is not null )


One error saving changes to table "PEL"."BESTELLPOS":

Row 4: ORA-04091: Tabelle PEL.BESTELLPOS wird gerade geändert, Trigger/Funktion sieht dies möglicherweise nicht

ORA-06512: in "PEL.TRIGGER1", Zeile 6

ORA-04088: Fehler bei der Ausführung von Trigger 'PEL.TRIGGER1'
Ich weiß das ist ein trigger Problem wegen mutating table bla und sollte mit new und old gelöst werden doch ich habe ja oben
:old.anzahl 

??

Bearbeitet von pel
Link zu diesem Kommentar
Auf anderen Seiten teilen

Stop, stop. Du musst unterschieden zwischen PL/SQL (eine prozedurale Programmiersprache) und SQL (eine Abfragesprache).

Obwohl man in PL/SQL eine SQL Abfrage ohne Probleme einfach so einbauen kann, sind das doch zwei Welten. Es finden intern auch ein Kontextswitch statt.

old ist eine PL/SQL variable. Um sie zuzuweisen brauchst Du nur den := Operator. Kein SELECT INTO.

Möchtest Du Daten aus einer Tabelle in einer Variable lesen brauchst Du ein SELECT INTO oder einen Cursor wenn es sich um mehr als einen Wert handelt.

Was Du machen möchtest sieht also so aus:

anzahl:=:old.anzahl;

Ich weiß das ist ein trigger Problem wegen mutating table

Das ist kein Triggerproblem, sondern eine Schutzmaßnahme, die von Oracle bewußt eingebaut wurde um dich davor zu bewahren aus einem Trigger heraus per SQL auf seine eigene Tabelle zuzugreifen.

Dim

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das ist kein Triggerproblem, sondern eine Schutzmaßnahme, die von Oracle bewußt eingebaut wurde um dich davor zu bewahren aus einem Trigger heraus per SQL auf seine eigene Tabelle zuzugreifen.

hehe das hat halt unsere Lehrerin behauptet die eh kein plan hat...

Ich poste mal die gesamte aufgabe damit klarer wird was ich will:

ayvd9zrokxfjyv842.png

Teillösung in worten... :

der temporäre Betrag ist = Rechnung.betrag * Bestellpos.anzahl Wo ART_Code = alter ART_Code ist ?

danach: neuer Rechnung.betrag = alter Rechnung.betrag - temporärer Betrag

In Worten und von der Logik dürfts hinkommen doch wie ich das in pl/sql ausdrücke komme ich net weiter, da die Unterlagen die ich hier habe unvollständig und verwirrend sind und so fühle ich mich auch...

Frage: Wie greife ich auf das "old" einer andere Tabelle als Bestellpos zu ?

Kennst du vielleicht einfach gehaltene trigger beispiele zum durchlesen etc?

Bearbeitet von pel
Link zu diesem Kommentar
Auf anderen Seiten teilen

Also eigentlich ist das die Art von Triggern, die man nie nie nie machen sollte. Logik in einem Trigger verstecken ist immer schlechtes Design und macht eine Anwendung schwer wartbar.

Und sowas lernt ihr dann. Seufz.

Was Du brauchst ist ein einfacher UPDATE:

UPDATE rechnung SET betrag=betrag-(select :old.anzahl*preis from artikel where art_code=:old.art_code)

WHERE rechnungsnr=:old.rechnungsnr

So in etwa sollte das laufen (ungetestet). Aber wie gesagt: Solltest Du sowas mal im Beruf machen, hof ich, dass dir ein Kollege das ganze sofort um die Ohren haut.

Dim

Link zu diesem Kommentar
Auf anderen Seiten teilen

Also eigentlich ist das die Art von Triggern, die man nie nie nie machen sollte. Logik in einem Trigger verstecken ist immer schlechtes Design und macht eine Anwendung schwer wartbar.

Und sowas lernt ihr dann. Seufz.

Was Du brauchst ist ein einfacher UPDATE:

UPDATE rechnung SET betrag=betrag-(select :old.anzahl*preis from artikel where art_code=:old.art_code)

WHERE rechnungsnr=:old.rechnungsnr
So in etwa sollte das laufen (ungetestet). Aber wie gesagt: Solltest Du sowas mal im Beruf machen, hof ich, dass dir ein Kollege das ganze sofort um die Ohren haut. Dim
ne ich wills ja so wie du machen ;-) ok danke dir geht! Frage: So müsste es doch auch gehen oder? mir gefällt die Syntax besser...
UPDATE rechnung SET betrag = betrag - (select :old.anzahl*preis from artikel where art_code=:old.art_code AND rechnungsnr=:old.rechnungsnr);
Ausgabe: DELETE FROM "PEL"."RECHNUNG" WHERE ROWID = 'AAADZEAAEAAAADdAAB' AND ORA_ROWSCN = '452495' and ( "RECHNUNGSNR" is null or "RECHNUNGSNR" is not null ) also gehts net weißt du warum? ...zu NULL nicht möglich... hm...
One error saving changes to table "PEL"."RECHNUNG":

Row 2: ORA-01407: Aktualisieren von ("PEL"."BESTELLPOS"."RECHNUNGSNR") zu NULL nicht möglich

Bearbeitet von pel
Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Update hat ein paar Schönheitsfehler. Zum einen gibts keine einschränkende WHERE-Bedingung im UPDATE. Sprich würde das ganze (theoretisch) funktionieren, würdest Du alle Sätze ind er tabelle auf den gleichen Wert setzen. Und zwar immer wenn der Trigger zündet.

Zum anderen greifst Du im Subselect auf eine Spalte des bereits gelöschten Satzes zu. Du musst unterscheiden zwischen der Spalte rechnungsnr in der Tabelle RECHNUNG und BESTELLPOS

Vielleicht wird es verständlicher mit einem Alias:

UPDATE rechnung rech 

   SET rech.betrag=rech.betrag-(select :old.anzahl*preis from artikel art where art.art_code=:old.art_code)

 WHERE rech.rechnungsnr=:old.rechnungsnr

Dim

Link zu diesem Kommentar
Auf anderen Seiten teilen

Vielleicht wird es verständlicher mit einem Alias:

UPDATE rechnung rech 

   SET rech.betrag=rech.betrag-(select :old.anzahl*preis from artikel art where art.art_code=:old.art_code)

 WHERE rech.rechnungsnr=:old.rechnungsnr

Dim

verständlicher net doch ich denke ich habs zu 70% ^^ kapiert jetzt:

betrag - (wert wird ausgerechnet mit altem art_code) ABER nur da wo die alte rechnungsnr gleich der rechnungsnr in der Rechnung Tabelle ist wird upgedatet.

Link zu diesem Kommentar
Auf anderen Seiten teilen

betrag - (wert wird ausgerechnet mit altem art_code) ABER nur da wo die alte rechnungsnr gleich der rechnungsnr in der Rechnung Tabelle ist wird upgedatet.

Genau.

Und richte Deiner Lehrerin aus, dass sie die FIAE's nicht schon in der Schule verderben soll. In einem Trigger kann man Historisierungsdaten wegschreiben, vielleicht einen Timestamp setzen, einen PK über eine Sequenze füllen aber das Berechnen eines fachlichen Wertes in einer anderen Tabelle - grauenhaft. Stell dir das in einer Anwendung mit 200 und mehr Tabellen vor. Nach 2 Monaten weiß keiner mehr wo was wie und wann gesetzt und berechnet wird.

Aber was red ich: Die hier solltens eigentlich wissen und machen den gleichen Schmarrn. Vielleicht ein ehemaliger Schüler deiner Lehrerin?

Dim

Link zu diesem Kommentar
Auf anderen Seiten teilen

Vielleicht ein ehemaliger Schüler deiner Lehrerin?

für so abwegig halte ich das gar net... :D

zu meiner vorherigen Aufgabe:

UPDATE rechnung SET r_datum = SYSDATE Where rechnungsnr =:old.rechnungsnr;

es scheint zu funzen mit dem DAtum oder würdest du obigen code noch umschreiben/optimieren?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wenn Du mit dem Update Statement das Datumsfeld einer Rechnung auf das jetztige Datum setzen möchtest, dann ist das so richtig.

Dim

ok danke dir so wollte ich das auch!

CREATE OR REPLACE PROCEDURE UPDATE_PRAEMIE AS
eine mehr philosophische Frage... 1.) Warum steht nach jedem Methodennamen "AS" ??? Ich meine was bringt das oder Sinn? Erschaffe oder ersetze eine Prozedur soundso als ?? als was ? 2.) Ich bekomme hierbei Fehlermeldungen 2 Stück doch was ist an der Syntax falsch?
CREATE OR REPLACE PROCEDURE UPDATE_PRAEMIE AS


  declare cursor Mitarbeiter_Cursor is select * from Mitarbeiter for update;

  MA_Daten Mitarbeiter%ROWTYPE; -- Die Datensatzstruktur Spalten/Datentypen befinden sich nur im Datensatz MA_Daten


  BEGIN


  OPEN Mitarbeiter_Cursor;

  FOR MA_Daten IN Mitarbeiter_Cursor -- Für jeden Datensatz MA_Daten der sich in dem Cursor(-Array) Mitarbeiter_Cursor befindet mache folgendes:

  LOOP -- ****************************


  if MA_Daten.MA_Praemie > 9000 then  MA_Daten.MA_Praemie:= MA_Daten.MA_Praemie * 1.15; -- 15 % mehr Praemie

      elsif MA_Daten.MA_Praemie > 5000 then  MA_Daten.MA_Praemie:= MA_Daten.MA_Praemie * 1.1; -- 10 % mehr Praemie

      elsif MA_Daten.MA_Praemie > 1000 then  MA_Daten.MA_Praemie:= MA_Daten.MA_Praemie * 1.05; -- 5 % mehr Praemie

  end if;


  END LOOP; -- ***************************

  CLOSE Mitarbeiter_Cursor;


  END UPDATE_PRAEMIE; 
Fehler:
Error(4,3): PLS-00103: Fand das Symbol "DECLARE" als eines der folgenden erwartet wurde:     begin function package pragma procedure subtype type use    <an identifier> <a double-quoted delimited-identifier> form    current cursor external language Das Symbol "begin" ersetzte "DECLARE", um fortzufahren. 
Error(22,54): PLS-00103: Fand das Symbol "end-of-file" als eines der folgenden erwartet wurde:     begin case declare end exception exit for goto if loop mod    null pragma raise return select update while with    <an identifier> <a double-quoted delimited-identifier>    <a bind variable> << close current delete fetch lock insert    open rollback savepoint set sql execute commit forall merge    pipe 
Alternative else if Lösung:
update Mitarbeiter set MA_Praemie = MA_praemie * 1.15  where current of Mitarbeiter_Cursor

Ich habe gegoogelt verstehe das where current of <cursorname> trotzdem nicht... kann mir das jemand kurz erklären? grob übersetzt: update Mitarbeiter Tabelle und dessen Spalte MA_Praemie mit 15 % wo der Cursor aktuell draufzeigt ?? Ist das so richtig gedünkt?

Bearbeitet von pel
Link zu diesem Kommentar
Auf anderen Seiten teilen

ok ist jetzt nur noch 1 Fehler ^^

Frage: Das unten ist Muster-Code-Lösung...

 declare

  cursor cur_mitarbeiter is select * from i33mitarbeiter for update;

  MA_Daten i33mitarbeiter%ROWTYPE; 
müsste der hintere codeteil nicht so heißen:

MA_Daten cur_mitarbeiter%ROWTYPE ??
grrrr... EDIT: OK habe den Fehler gefunden es fehlte ein BEGIN UNd habe die Prozedur ausgeführt: bekomme diese Meldung im Log:
Connecting to the database MyConnection.

ORA-06511: PL/SQL: Cursor wurde bereits geöffnet

ORA-06512: in "PEL.UPDATE_PRAEMIE", Zeile 5

ORA-06512: in "PEL.UPDATE_PRAEMIE", Zeile 11

ORA-06512: in Zeile 2

Prozess beendet.

Disconnecting from the database MyConnection.
Beispiel error:
ORA-06512 at string line string


    Cause: Backtrace message as the stack is unwound by unhandled exceptions.


    Action: Fix the problem causing the exception or write an exception handler for this condition. Or you may need to contact your application administrator or database administrator

.

Was kann das ein?

Dazu muss ich sagen, dass manche Mitarbeiter eine Prämie von 0 haben. Spielt das ein Problem?

Bearbeitet von pel
Link zu diesem Kommentar
Auf anderen Seiten teilen

Wenn ich den cursor nicht öffne gehts sprich keine Fehlermeldung mehr doch die Prämien werden nicht geupdatet... ABER man muss doch einen Cursor öffnen das verstehe ich jetzt net...

Weiterhin verwirrt mich und ich habe auf Wikipedia geschaut:

MA_Daten Mitarbeiter_Cursor%ROWTYPE;
Mitarbeiter_Cursor ist ein Cursor! Lehrerin schreibt in der Lösung die net funzt...:
MA_Daten Mitarbeiter%ROWTYPE;
Mitarbeiter ist eine Tabelle! Wie ist die Syntax jetzt richtig?
MA_Daten <Tabellename>%ROWTYPE  
oder
MA_Daten <Cursorname>%ROWTYPE  

??

Link zu diesem Kommentar
Auf anderen Seiten teilen

Also Deine Lehrerin sollte ihre Kenntnisse wirklich mal auffrischen...

Fangen wir mit dem einfachen an.

OPEN Mitarbeiter_Cursor;

  FOR MA_Daten IN Mitarbeiter_Cursor
Die FOR Cursor Syntax gibt es seit 9i. Dabei übernimmt Oracle das öffnen und schließen des Cursors. Daher der Fehler weil Du den Cursor selbst öffnest und Oracle es dann nochmal versucht. Du kannst auch folgendes schreiben:
 FOR myrecord IN (select col1,col2,col3 FROM tabelle) LOOP ... END LOOP
Ist aber etwas unübersichtlich wenn das SQL umfangreicher wird, daher verwende ich diese Syntax eher sparsam.
Wie ist die Syntax jetzt richtig?
Beides. Das einemal erzeugst Du einen Record vom Typ der Tabelle, das andere legt einen Record vom Typ eines Cursors an. Du brauchst wohl eher einen Record auf den Cursors, wobei der bei einem SELECT * identisch mit der Tabelle ist.
 if MA_Daten.MA_Praemie > 9000 then  MA_Daten.MA_Praemie:= MA_Daten.MA_Praemie * 1.15; -- 15 % mehr Praemie

      elsif MA_Daten.MA_Praemie > 5000 then  MA_Daten.MA_Praemie:= MA_Daten.MA_Praemie * 1.1; -- 10 % mehr Praemie

      elsif MA_Daten.MA_Praemie > 1000 then  MA_Daten.MA_Praemie:= MA_Daten.MA_Praemie * 1.05; -- 5 % mehr Praemie

  end if;
Mir wär' nicht bekannt, das diese Sytanx zu einem Update einer Tabelle führt. Sieht schön aus der Nutzwert dürfte sich aber gegen 0 bewegen.
Mitarbeiter set MA_Praemie = MA_praemie * 1.15  where current of Mitarbeiter_Cursor
Dies ist die richtige Syntax. Damit wird der Satz, auf welchen der Cursor aktuell "zeigt" updgedated. Allerdings hat diese Aufgabe einen gravierenden Fehler: Sie zeigt wie man es nicht machen soll. Ihr bekommt hier grade die langsamste Methode gezeigt eine Tabelle zu ändern. Erste Regel wenn man mit PL/SQL und Cursors arbeitet: Mache nichts mit PL/SQL wenn Du es mit einem einzigen Statement machen kannst:

update mitarbeiter a set praemie=(select case when praemie > 9000 then praemie*1.15

                                           when praemie > 5000 then praemie*1.1

                                           when praemie > 1000 then praemie*1.05

                                      end case

                                 from mitarbeiter b

                                 where a.id=b.id)

Allerdings ist diese Abfrage auch etwas seltsam, denn ein Mitarbeiter der 9001 bekommt, ist sowohl größer als 1000 und 5000 und 9000. Aber das müsst ihr wissen ;)

Dim

Bearbeitet von dr.dimitri
Link zu diesem Kommentar
Auf anderen Seiten teilen

wie du gesagt hast keine fachliche logik in einen trigger.... kann ich dann ich einem trigger eine Funktion/Prozedur aufrufen, die dann z.B. Prämien updated oder wäre das doppelt gemoppelt?

Was ist denn der praktische/alltäglich Anwendungsfall von Triggern, sprich Datensatz wird gelöscht/updated/inserted und dann?? was passiert dann hier meistens?

Das habe ich noch vom oracle forum gefällt mir auch gut:

update Mitarbeiter

   set MA_Praemie =

       case

       when MA_Praemie > 9000 then MA_Praemie * 1.15

       when MA_Praemie > 5000 then MA_Praemie * 1.10

       when MA_Praemie > 1000 then MA_Praemie * 1.05

       else MA_Praemie

       end
also open cursor nur mit der for ...in... cursor schleife OK! Kannst du erkennen warum ich hier für eine Prämie von 8000 (+10%) einen wert von 22390.. bekomme ???
create or replace

PROCEDURE UPDATE_PRAEMIE AS

BEGIN 


  DECLARE 

  CURSOR Mitarbeiter_Cursor is select * from Mitarbeiter for update;

  MA_Daten Mitarbeiter%ROWTYPE; -- Die Datensatzstruktur Spalten/Datentypen befinden sich nur im Datensatz MA_Daten


    BEGIN


    --OPEN Mitarbeiter_Cursor;

        FOR MA_Daten IN Mitarbeiter_Cursor -- Für jeden Datensatz MA_Daten der sich in dem Cursor(-Array) Mitarbeiter_Cursor befindet mache folgendes:

        LOOP -- **********************************************************************************************************

       -- FETCH Mitarbeiter_Cursor INTO ma_daten;


      update Mitarbeiter  set MA_Praemie =

         case

         when MA_Praemie > 9000 then MA_Praemie * 1.15

         when MA_Praemie > 5000 then MA_Praemie * 1.10

         when MA_Praemie > 1000 then MA_Praemie * 1.05

         else MA_Praemie

         end;


        EXIT WHEN Mitarbeiter_Cursor%NOTFOUND;        

        END LOOP; -- *****************************************************************************************************

    --CLOSE Mitarbeiter_Cursor;

    END;

COMMIT;

END UPDATE_PRAEMIE; 

Link zu diesem Kommentar
Auf anderen Seiten teilen

wie du gesagt hast keine fachliche logik in einen trigger.... kann ich dann ich einem trigger eine Funktion/Prozedur aufrufen, die dann z.B. Prämien updated oder wäre das doppelt gemoppelt?

Ja kannst Du, aber damit verlagerst Du nur das Sympthom. Ein Tigger soll nicht nur keine fachliche Logik enthalten, er soll sie auch nicht aufrufen. Streich das am besten sofort weder aus deinem Kopf. Der Update soll aus dem Programm aufgerufen werden. Der beste Weg ist, alles in eine Procedur zu stecken, die dann z.B. per Java o.ä. mit entsprechenden Parametern aufgerufen wird.

Kein Trigger der dazu führt, das irgend etwas "magisches" passiert. Wie gesagt stell dir eine AW mit 200 Tabellen vor, die auf diese "Technik" zurückgreift. Dazu gibts noch 10 Entwickler und jeder schreibst so seine persönlichen Zauberkunststücke in diverse Trigger. Glaubst Du, da blickt nach einer gewissen Zeit noch einer durch?

Trigger können dazu verwendet werden um z.B. Änderungen zu loggen und Historisierungstabellen mit den alten Werten zu befüllen. Es gibt bei uns ca. 250 Trigger, von denen etwa 99% über Skripte generiert werden und die nichts anderes machen als einen Timestamp zu setzen und Werte wegzuschreiben.

also open cursor nur mit der for ...in... cursor schleife OK!

Eigentlich sollte man nur noch FOR record IN cursor LOOP verwenden. Dann braucht man sich nicht um die Freigabe von Ressourcen kümmern - auch nicht im Fehlerfall. Dein EXIT WHEN ist ebenfalls überflüssig. PL/SQL beendet die Schleife selbst wenn ales gelesen wurde.

update Mitarbeiter

set MA_Praemie =

case

when MA_Praemie > 9000 then MA_Praemie * 1.15

when MA_Praemie > 5000 then MA_Praemie * 1.10

when MA_Praemie > 1000 then MA_Praemie * 1.05

else MA_Praemie

end

Ja stimmt - das von mir war natürlich doppelt gemoppelt. Das wär die korrekte Lösung.

Kannst du erkennen warum ich hier für eine Prämie von 8000 (+10%) einen wert von 22390.. bekomme ???

Weil Du die Prozedure 8 mal ausgeführt hast.

    END;

COMMIT;

END UPDATE_PRAEMIE;

Wenn Du das in einen Trigger einbaust gibt es einen Fehler, da in einem Trigger nicht committed werden darf. Eine weitere Schutzfunktion.

ich hab übrigends vor einiger Zeit mal einen kleinen Artikel zu Cursor geschrieben. Vielleicht hilft dir das weiter: PL/SQL Cursor Tipps

Dim

Link zu diesem Kommentar
Auf anderen Seiten teilen

super man deine Antworten sind echt hilfreich!

Syntax von Select:

SELECT column_name(s) FROM table_name
warum dann das?

cursor cur_mitarbeiter is select * from i33mitarbeiter for update;
warum das for update hinten? würde es nicht auch so ok sein?:
cursor cur_mitarbeiter is select * from i33mitarbeiter ;

warum brauche ich in einer Funktion kein declare(compiler meckert) aber in einer Prozedur schon? Wo ist da der Sinn?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Zitat:

Kannst du erkennen warum ich hier für eine Prämie von 8000 (+10%) einen wert von 22390.. bekomme ???

Weil Du die Prozedure 8 mal ausgeführt hast.

ja die prozedur habe ich nur 1x aufgerufen, doch was 8 mal passiert ist dies:

das ist doch richtig so, dass für jedes element im cursor die Prämie geupdated wird, was ist daran falsch? laut meinem ergebnis müsste bei 8 tupel ja 8 durchläufe und dazu je 8 updates geschehen tuts doch aber nicht, sorry steh auf dem Schlauch :D

 FOR MA_Daten IN Mitarbeiter_Cursor -- Für jeden Datensatz MA_Daten der sich in dem Cursor(-Array) Mitarbeiter_Cursor befindet mache folgendes:

        LOOP -- **********************************************************************************************************

       -- FETCH Mitarbeiter_Cursor INTO ma_daten;


      update Mitarbeiter  set MA_Praemie =

         case

         when MA_Praemie > 9000 then MA_Praemie * 1.15

         when MA_Praemie > 5000 then MA_Praemie * 1.10

         when MA_Praemie > 1000 then MA_Praemie * 1.05

         else MA_Praemie

         end;


        EXIT WHEN Mitarbeiter_Cursor%NOTFOUND;        

        END LOOP; -- *****************************************************************************************************

Link zu diesem Kommentar
Auf anderen Seiten teilen

cursor cur_mitarbeiter is select * from i33mitarbeiter for update;

Mit einem FOR UPDATE sperrst Du die selektierten Sätze für andere Sessions. Sie können gelesen aber nicht mehr geändert werden bis deine Session die Transaktion mit COMMIT oder ROLLBACK beendet.

Ohne FOR UPDATE könnte eine andere Session die Sätze ändern und Du müsstest warten bis Du schreiben kannst. Hättest dann aber den Wert des anderen überschrieben.

Das Thema Multiuser ist ein eigenes Kapitel für sich und es gibt zwei verschiedene Ansätze dafür. Zum einen das pessimistische Locking (das was Du machst) oder das optimistische Locking (erst locken bevor geschrieben wird und dabei prüfen ob sich der Wert in der Zwischenzeit geändert hat).

Meistens wird das optimitische Locking verwendet, da ansonsten immer sehr viele Datensätze für andere Sessions gesperrt wären.

laut meinem ergebnis müsste bei 8 tupel ja 8 durchläufe und dazu je 8 updates geschehen tuts doch aber nicht, sorry steh auf dem Schlauch

Keine Ahnung was Du da drumherumprogrammiert hast. Auf jeden Fall ist dein Cursor unnötig und versaut dir dein Ergebnis. Du brauchst keine Schleife und keinen Cursor - dein UPDATE Befehl macht alles in einem Rutsch.

Dim

Bearbeitet von dr.dimitri
Link zu diesem Kommentar
Auf anderen Seiten teilen

Keine Ahnung was Du da drumherumprogrammiert hast. Auf jeden Fall ist dein Cursor unnötig und versaut dir dein Ergebnis. Du brauchst keine Schleife und keinen Cursor - dein UPDATE Befehl macht alles in einem Rutsch.
so gehts: ok ich versuchte immer eine update auf einzelne Zeilen zu machen, wobei update ja beinhaltet, dass die ganze TAbelle betroffen ist :schlaf: :D
create or replace

PROCEDURE UPDATE_PRAEMIE AS

BEGIN 


    BEGIN   


      update Mitarbeiter  set MA_Praemie =

         case

         when MA_Praemie > 9000 then MA_Praemie * 1.15

         when MA_Praemie > 5000 then MA_Praemie * 1.10

         when MA_Praemie > 1000 then MA_Praemie * 1.05

         else MA_Praemie

         end;


    END;

COMMIT;

END UPDATE_PRAEMIE; 
meine Verwirrung insgesamt beruht auf diesen 2 Lösungen der Lehrerin...

create or replace PROCEDURE I33UPDATE1_PRAEMIE AS

BEGIN

  declare

  cursor cur_mitarbeiter is select * from i33mitarbeiter for update;

  MA_Daten i33mitarbeiter%ROWTYPE; 


  BEGIN

    for MA_Daten  in cur_mitarbeiter

    loop

      if MA_Daten.MA_Praemie > 9000 then  MA_Daten.MA_Praemie:= MA_Daten.MA_Praemie * 1.15;

         --    Alternative:

         --    then update i33mitarbeiter set MA_Praemie = MA_praemie * 1.15  where current of cur_mitarbeiter

         elsif MA_Daten.MA_Praemie > 5000

               then  MA_Daten.MA_Praemie:= MA_Daten.MA_Praemie * 1.1;

               --    s.o.

               elsif MA_Daten.MA_Praemie > 1000

                     then  MA_Daten.MA_Praemie:= MA_Daten.MA_Praemie * 1.05;

                     -- s.o.

    end if;

    -- für alternative Lösung nicht:

    update i33mitarbeiter set MA_Praemie = MA_Daten.MA_Praemie where 

           MA_Nr = MA_Daten.MA_Nr;

    end loop;


  end;

  commit;


END I33UPDATE1_PRAEMIE;



create or replace PROCEDURE I33UPDATE2_PRAEMIE AS

BEGIN

  declare

  cursor cur_mitarbeiter is select * from i33mitarbeiter for update;

  MA_Daten i33mitarbeiter%ROWTYPE; 


  BEGIN

    open cur_mitarbeiter;

    loop

    fetch cur_mitarbeiter into MA_Daten;

      if MA_Daten.MA_Praemie > 9000  then  MA_Daten.MA_Praemie:= MA_Daten.MA_Praemie * 1.15;

         --    Alternative:

         --    then update i33mitarbeiter set MA_Praemie = MA_praemie * 1.15 where current of cur_mitarbeiter

         elsif MA_Daten.MA_Praemie > 5000

               then  MA_Daten.MA_Praemie:= MA_Daten.MA_Praemie * 1.1;

               --    s.o.

               elsif MA_Daten.MA_Praemie > 1000

                     then  MA_Daten.MA_Praemie:= MA_Daten.MA_Praemie * 1.05;

                     -- s.o.

    end if;

    -- für alternative Lösung nicht

    update i33mitarbeiter set MA_Praemie = MA_Daten.MA_Praemie where MA_Nr = MA_Daten.MA_Nr;

    exit when cur_mitarbeiter%NOTFOUND;

    end loop;


    close cur_mitarbeiter;


  end;

  commit;

END I33UPDATE2_PRAEMIE;



Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...