dr.dimitri Geschrieben 25. Mai 2008 Teilen Geschrieben 25. Mai 2008 warum brauche ich in einer Funktion kein declare(compiler meckert) aber in einer Prozedur schon? Wo ist da der Sinn? 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 Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
dr.dimitri Geschrieben 25. Mai 2008 Teilen Geschrieben 25. Mai 2008 meine Verwirrung insgesamt beruht auf diesen 2 Lösungen der Lehrerin Ja da wär ich auch verwirrt. Schon interessant wie man ein einfaches UPDATE aufblähen kann. Dim Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
pel Geschrieben 25. Mai 2008 Autor Teilen Geschrieben 25. Mai 2008 (bearbeitet) 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 warum meckert der compiler aber, wenn untenstehends declare von mir entfernt wird? Es ist eine Prozedur sollte doch laut dir kein declare enthalten? CREATE OR REPLACE PROCEDURE COLLECTIONTEST AS BEGIN declare 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; Beende ich ein Case mit end case; kommt Fehler. nur mit end; kein fehler?? In wikipedia steht aber end case; so beenden :confused: irgendwie scheint mir pl/sql noch in den Kinderschuhen zu stecken oder die leute blickens net... quelle: http://de.wikipedia.org/wiki/PL/SQL#Simple_CASE beides zu erlauben ist auch quark! Bearbeitet 25. Mai 2008 von pel Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
dr.dimitri Geschrieben 25. Mai 2008 Teilen Geschrieben 25. Mai 2008 irgendwie scheint mir pl/sql noch in den Kinderschuhen zu stecken oder die leute blickens net... Letzteres. Was ihr in der Schule beigebracht bekommt ist ja sowas von falsch, das es schon nicht mehr feierlich ist warum meckert der compiler aber, wenn untenstehends declare von mir entfernt wird? 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; In wikipedia steht aber end case; so beenden Lass mal die wikipedia und schau lieber in der Doku nach: Fundamentals of the PL/SQL Language Dim Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
pel Geschrieben 25. Mai 2008 Autor Teilen Geschrieben 25. Mai 2008 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; Fehler: Error(12,1): PLS-00103: Fand das Symbol "END" ?? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
dr.dimitri Geschrieben 25. Mai 2008 Teilen Geschrieben 25. Mai 2008 Ich hab vergessen ein überflüssiges END rauszuwerfen. Dim Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
pel Geschrieben 25. Mai 2008 Autor Teilen Geschrieben 25. Mai 2008 kennst du noch ein Programm sollte freeware sein, dass pl/sql code darstellt mit syntax highlighting, da ich meinen Code farbig ausdrucken möchte, um zu lernen ach vergiß die frage, ich installier einfach sql developer bei der Freundin daheim... Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
pel Geschrieben 25. Mai 2008 Autor Teilen Geschrieben 25. Mai 2008 Musterlösung von Lehrerin: create or replace PROCEDURE STUE14 AS BEGIN declare cursor c_Bestellung is select * from BestellungenUe14 where Lfr_code not in (select Lfr_code from LieferantenUe14) for update; B_Satz BestellungenUe14 %ROWTYPE; fehlercode number; fehlernachricht varchar2(255); lfr_not_found exception; falscherLfr_code BestellungenUe14.Lfr_code%TYPE; -- B_Satz.Lfr_code in exception nicht -- bekannt! Begin dbms_output.enable; if SQL%NOTFOUND then dbms_output.put_line('keine fehlerhaften Tupel in B-Tab.'); else for B_Satz in c_Bestellung loop insert into FalscheBestellungenUe14 values (B_Satz.Bestellnr, B_Satz.Lfr_code, B_Satz.B_Datum, B_Satz.Betrag); delete BestellungenUe14 where current of c_Bestellung; falscherLfr_code:= B_Satz.Lfr_code; raise lfr_not_found; end loop; end if; commit; exception when NO_DATA_FOUND then dbms_output.put_line('keine fehlerhaften Tupel in Bestell-Tab.'); when lfr_not_found then dbms_output.put_line('Lieferant: '||falscherLfr_code||' ex. nicht'); when others then fehlercode:= SQLCODE; fehlernachricht:= SQLERRM; end; DDL code von Lehrerin: CREATE TABLE BESTELLUNGENUE14 ( "BESTELLNR" NUMBER(10,0), "LFR_CODE" CHAR(3), "B_DATUM" CHAR(8), "BETRAG" NUMBER(7,2) ) ; Insert into BESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (175,'004','19880227',395.51); Insert into BESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (181,'009','19890306',577.22); Insert into BESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (190,'014','19850313',659.84); Insert into BESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (191,'013','19850313',1211.41); Insert into BESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (200,'004','20040314',72); Insert into BESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (201,'004','19850326',221.25); Insert into BESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (202,'014','19850326',530.43); Insert into BESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (203,'019','19850401',556.6); Insert into BESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (205,'013','20010225',300); CREATE TABLE FALSCHEBESTELLUNGENUE14 ( "BESTELLNR" NUMBER(10,0) NOT NULL ENABLE, "LFR_CODE" CHAR(3), "B_DATUM" CHAR(8), "BETRAG" NUMBER(7,2) ) ; ALTER TABLE FALSCHEBESTELLUNGENUE14 ADD CONSTRAINT "FALSCHEBESTELLUNGENUE18_PK" PRIMARY KEY ("BESTELLNR") ENABLE; Insert into FALSCHEBESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (174,'003','20010225',117.5); Insert into FALSCHEBESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (184,'022','19990306',240); Insert into FALSCHEBESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (186,'020','19850311',414.05); Insert into FALSCHEBESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (192,'035','20030313',317.52); Insert into FALSCHEBESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (197,'035','19850314',928.27); Insert into FALSCHEBESTELLUNGENUE14 (BESTELLNR,LFR_CODE,B_DATUM,BETRAG) values (204,'034','19850401',492.53); CREATE TABLE LIEFERANTENUE14 ( "LFR_CODE" CHAR(3) NOT NULL ENABLE, "LFR_NAME" VARCHAR2(20), "ADRESSE" VARCHAR2(25), "WOHNORT" VARCHAR2(15) ) ; ALTER TABLE LIEFERANTENUE14 ADD CONSTRAINT "LIEFERANTENUE18_PK" PRIMARY KEY ("LFR_CODE") ENABLE; Insert into LIEFERANTENUE14 (LFR_CODE,LFR_NAME,ADRESSE,WOHNORT) values ('004','HOVEN G.H.','SANDWEG 50','LINZ'); Insert into LIEFERANTENUE14 (LFR_CODE,LFR_NAME,ADRESSE,WOHNORT) values ('009','BAUMGARTEN R.','TANKSTRASSE 13','HANNOVER'); Insert into LIEFERANTENUE14 (LFR_CODE,LFR_NAME,ADRESSE,WOHNORT) values ('011','STRAUCH GMBH','BEERENWEG 1','LINZ'); Insert into LIEFERANTENUE14 (LFR_CODE,LFR_NAME,ADRESSE,WOHNORT) values ('013','SPITZMANN','HINTERGARTEN 9','AALEN'); Insert into LIEFERANTENUE14 (LFR_CODE,LFR_NAME,ADRESSE,WOHNORT) values ('014','DEZAIER L.J.','IM GRUND 101','LINZ'); Insert into LIEFERANTENUE14 (LFR_CODE,LFR_NAME,ADRESSE,WOHNORT) values ('019','SCHOENE F.A.','SOMMERSTR. 24','AALEN'); Compiliert OK, doch beim ausführen der Prozedur kommt dieser fehler: Source does not have a runnable target. Habe auch gegoogelt doch da steht was von Packages macht aber net wirklich sinn, vielleicht weißt du mehr mit deiner Masse ERahrung an pl/sql!? :uli Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
pel Geschrieben 25. Mai 2008 Autor Teilen Geschrieben 25. Mai 2008 jetzts gehts plötzlich... komisch Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
dr.dimitri Geschrieben 25. Mai 2008 Teilen Geschrieben 25. Mai 2008 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. "BESTELLNR" NUMBER(10,0) NOT NULL ENABLE, 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 SQLKeine Programmlogik innerhalb eines Triggers (auch keine die aus einem Trigger heraus aufgerufen wird)Ein WHEN OTHERS ohne abschließendes RAISE ist zu 99% ein BugVerwende geschachtelte BEGIN END Blöcke um die Fehlerbehandlung zu verfeinen. Aber verwende kein DECLAREDiesen Link bookmarken: Oracle Database Online Documentation 10g Release 2 (10.2) Dim Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Empfohlene Beiträge
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.