Zum Inhalt springen

dr.dimitri

Mitglieder
  • Gesamte Inhalte

    1276
  • Benutzer seit

  • Letzter Besuch

Alle Inhalte von dr.dimitri

  1. Seit 9i gibt es auch die JOIN Sytanx. Vorher gab es nur den Kommajoin. Vom Ausführungsplan her sind sie aber identisch. Dim
  2. Kommt drauf an. Manche Datenbanken (vor allem ältere Mysql Versionen) haben beim sog. "Kommajoin" einen schlechteren Ausführungsplan als wenn Du die ANSI Syntax verwendest. Bei anderen sollte es egal sein. ich persönlich finde die Schreibweise ohne das JOIN Schlüsselwort einfach zu lesen und auch schneller zu schreiben. Beachte auch, dass Du bei der JOIN Schreibweise zwischen JOIN Bedingung und WHERE Bedingung unterscheiden musst. Auch das ist beim Kommajoin m.M. nach eleganter. Im Prinzip aber alles Geschmackssache. Dim
  3. Also Oracle bietet dafür einen eigenen datentyp an: Timestamp. Dieser enthält auch die Zeitzone (bei bedarf). Ansonsten muss man sich das in der Tabelle selbst speichern in welcher Zeitzone das Datum eingegeben wurde und ggf. eine Umrechung vor die Anzeige schalten. In diversen Foren kann man ja auch selbst wählen in welcher Zeitzone man sich befindet und wie die Zeit dementsprechend angezeigt werden soll. Dim
  4. Ist aber nicht so in Deinem Beispiel. Ich hab mal kurz in die Doku geschaut und das scheint wohl rein syntaktisch zu stimmen. Am besten wär natürlich, wenn du dir eine mysql, oracle XE oder postgres Datenbank installieren würdest um direkt üben zu können. Dim
  5. Ich kann nicht beurteilen ob die syntax richtig ist, da ich nicht weiß welche DB du verwendest allerdings legt ein FK Constraint kein eigenes Feld an. Das musst schon vorhanden sein. Du benötigst in Person also noch ein Feld Zimmernr. Dim
  6. Um eine FK beziehung anzulegen, brauchst Du, wie Du schon richtig gesagt hast, zwei Tabellen, wobei mindestens die übergeordnete einen PK Constraint benötigt. In der untergeordneten Tabelle brauchst Du ein Feld, welches die Werte aus der übergeordneten tabelle aufnehmen kann. Im allgemeinen verwendet man dafür ein extra Feld und legt keinen PK Constraint darauf, da es ansonsten auch direkt eine 1:1 Beziehung wäre. Beispiel: create table person(id number primary key, name varchar2(50), vname varchar2(50), gebdat date); create table haus(id number primary key, ort varchar2(50), strasse varchar2(50), plz varchar2(10)); create table hausbewohner(id number primary key, bewohnerid number [b]references person[/b], hausid number [b]references haus[/b]); Die Tabelle Hausbewohner referenziert über das Feld bewohnerid die Tabelle Person und über das Feld hausid die Tabelle Haus. damit hast Du eine Struktur, mit der Du eine Person einem, mehreren oder auch gar keinem Haus zuordnen kannst. Solange eine Zuordnung besteht, kann ein Eintrag in Person oder Haus nicht gelöscht werden. Eine Löschweitergabe würde mit dem Befehl references person on delete cascade (analog für den FK auf Haus) erreicht werden. Dim PS: Diese Syntax ist gültig wenn du eine Oracle DB verwendest. Andere Datenbanken können eine andere Syntax verwenden.
  7. So ganz bin ich nicht durchgestiegen. Meinst Du etwa sowas: SELECT * FROM TAB_B WHERE TAB_B.VerbundFK = 'Test' [b]AND spalte2='wert2'[/b] Dim
  8. PL/SQL ist Oracle nicht mysql. Dim
  9. Also meine Meinung über eure Lehrerin was PL/SQL angeht wird immer schlechter echt. Man kann eigentlich nur raten es nicht so zu machen wie es hier gezeigt wird. Da wär ja zum einen wieder der unnötig geschachtelte declare-begin-end block. Dann diese bedingung hier: if SQL%NOTFOUND then dbms_output.put_line('keine fehlerhaften Tupel in B-Tab.'); Ja ne ist klar. Welches SQL wurde denn bitte ausgeführt um überhaupt ein aussagekräftiges Ergebnis zu bekommen? Keines. Ist also ein ganz klarer Bug. Dann das Exception Handling. Wird ein fehlerhafter Satz gefunden, gibts einen Eintrag in eine Logtabelle, es wird etwas gelöscht und anschließend wird eine Exception geworfen, welche direkt in den EXCEPTION Block verzweigt. Und dann? Ich hab hier eine offene Transaktion. das Commit wird nämlich nicht ausgeführt. Wir hätten also Bug Nr.2 Ausserdem wärs doch schöner, wenn ich nicht beim ersten Fehler komplett rausspring und dann nochmal starten muss um den nächsten zu finden und so weiter und so fort. Bug Nr. 3 Im Exceptionblock gehts aber natlos weiter. Ein explizieter Cursor wirft keine NO_DATA_FOUND Exception. das wird hier aber erwartet. Bug Nr. 4 Im WHEN OTHERS Block wird die Fehlermeldung einer Variablen eines eines einbebetteten PL/SQL Blocks zugewiesen und das Programm anschließend beendet. Leider ist die innere Variable aber im äußeren Block nicht sichtbar und daher könnte die Fehlermeldung nicht ausgelesen werden (Bug Nr 5) noch ist ein abschließendes RAISE vorhanden, welches die Fehlermeldung weitergibt (Bug Nr.6). DDL code von Lehrerin: Ja da geht es munter weiter. Zum einen wird suggeriert, das man "" um die Spaltennamen braucht. Das ist nicht so. Es ist sogar gefährlich. Ist alles groß geschrieben passiert nichts. Legt man jetzt aber z.B. eine solche Tabelle an: SQL> create table never_do_that("Spalte1" number); Tabelle wurde erstellt. SQL> select spalte1 from never_do_that; select spalte1 from never_do_that * FEHLER in Zeile 1: ORA-00904: "SPALTE1": ungültiger Bezeichner SQL> select "Spalte1" from never_do_that; Es wurden keine Zeilen ausgewählt es wurde also erreicht, dass der Spaltenname plötzlich Casesensitive angegeben werden muss!! Also bei DDL generell keine "" verwenden. Auch wenn manche Tools das so generieren bzw. Oracle das intern so umwandelt. Das ENABLE ist unnötig, das NOT NULL ist, wenn man den später angelegten zweiten Constraint sieht auch unnötig. Eine PrimaryKey ist immer impliziert indiziert, unique und not null. Hier wurden zwei gleiche Constraints auf die Spalte gelegt - und es wird dementsprechend auch zweimal geprüft. Zusammengefasst nochmal das wichtigste für dich als Einsteiger: Verwende niemals PL/SQL wenn es es mit SQL geht. Und es geht sehr viel mit reinem SQL Keine Programmlogik innerhalb eines Triggers (auch keine die aus einem Trigger heraus aufgerufen wird) Ein WHEN OTHERS ohne abschließendes RAISE ist zu 99% ein Bug Verwende geschachtelte BEGIN END Blöcke um die Fehlerbehandlung zu verfeinen. Aber verwende kein DECLARE Diesen Link bookmarken: Oracle Database Online Documentation 10g Release 2 (10.2) Dim
  10. Ich hab vergessen ein überflüssiges END rauszuwerfen. Dim
  11. Letzteres. Was ihr in der Schule beigebracht bekommt ist ja sowas von falsch, das es schon nicht mehr feierlich ist Du kannst in PL/SQL Blöcke inneinander schachteln. Das wird z.B. verwendet um im Falle einer Exception nicht sofort ans ende der Prozedur zu springen: create procedure t is begin ... --Hier beginnt ein eingebetteter Block begin ... exception when ... end; ... --Hier beginnt ein eingebetteter Block begin ... exception when ... end; --Hier endet er ... exception when others then --Alle nicht behandelten Fehler werden hier behandelt dbms_output.put_line('Unbekannter Fehler aufgetreten: '||SQLERRM); raise; end; Damit hast Du zwei separate Blöcke mit einer eigenen Fehlerbehandlung. In Java wär das vergleichbar mit einem try-catch Block. Fügt man aber noch ein declare hinzu (ist ja erlaubt da es nicht zur Prozedur sondern zum eingebetteten Block gehört) wird das ganze eher vergleichbar mit einer Inneren Klasse. In java mag es Konstrukte geben in denen das sinnvoll sein mag, in PL/SQL gehört das in die Kategorie "schwer wartbarer Code" bzw. "denn sie wissen nicht was sie tun". Bei dir wäre also folgendes korrekt: CREATE OR REPLACE PROCEDURE COLLECTIONTEST AS TYPE MaTab is table of Mitarbeiter%ROWTYPE index by binary_integer; MaSatz MaTab; BEGIN -- ///////// Spaltenwerte in eine Collections einlesen ///////////// select * into MaSatz(1) from mitarbeiter where ma_nr = 1; dbms_output.put_line('Mitarbeiternummer: '||masatz(1).MA_NR||' Vorname: '||masatz(1).MA_Vorname||' Mitarbeitergehalt: '||masatz(1).MA_Gehalt); End; END COLLECTIONTEST; Lass mal die wikipedia und schau lieber in der Doku nach: Fundamentals of the PL/SQL Language Dim
  12. Ja da wär ich auch verwirrt. Schon interessant wie man ein einfaches UPDATE aufblähen kann. Dim
  13. Ein DECLARE ist weder in einer Prozedur noch in einer Funktion erlaubt. Das Schlüsselwort existitiert in Tiggern und anonymen PL/SQL Blöcken. Dim
  14. 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. 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
  15. 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. 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. Ja stimmt - das von mir war natürlich doppelt gemoppelt. Das wär die korrekte Lösung. 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
  16. 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
  17. Wenn Du mit dem Update Statement das Datumsfeld einer Rechnung auf das jetztige Datum setzen möchtest, dann ist das so richtig. Dim
  18. 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
  19. 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
  20. 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
  21. 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; 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
  22. Das sind Standardwerte. Zu sagen, dass man OLD als old ansprechen möchte ist relativ sinnfrei. 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
  23. 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; / 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
  24. Na zumindest bei den 10ern könnt ihr dann ja auch flashback database verwenden (falls ihr das nicht schon macht). Damit läßt sich schon mal einiges wieder herstellen ohne gleich recovern zu müssen - besonders bei operationalen Beständen sollte das helfen. Dispositove werden ja meinsten eh nach dem laden nicht mehr geändert. Dim
  25. Welche Version verwendet ihr denn eigentlich?

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...