Einführung in Datenbanken Semester: IV DATENBANKEN I Semester 4 Mitgeschrieben von: Isabel Drost, If99w1 Mitschrift von: Drost, Isabel/ if99wp1 Seite 1 von 23 Einführung in Datenbanken Semester: IV Inhaltsverzeichnis: ZIELE: ___________________________________________________________________4 Mittel(SE):_________________________________________________________________4 Aufgaben: _________________________________________________________________4 SQL – formale Sprache __________________________________________________________ 4 Oracle SQL+: ______________________________________________________________4 Data Types_________________________________________________________________5 Konkrete Operationen _______________________________________________________5 Projektionen - Spaltenauswahl ____________________________________________________ 5 SCOTT ........ Lsg.: SELECT ename „Name“, ‚........‘ „Unterschrift“ __________________________ 5 Selection – Auswahl von Zeilen____________________________________________________ 6 Wildcards__________________________________________________________________6 Ordnung __________________________________________________________________7 Mengen ___________________________________________________________________7 Nullwerte __________________________________________________________________8 Join ______________________________________________________________________8 Outer Join _____________________________________________________________________ 9 AutoJoin ___________________________________________________________________________ 10 TetaJoin Θ __________________________________________________________________ 10 BETWEEN – Operator _________________________________________________________ 10 Das Karthesische Produkt ___________________________________________________10 Subquery _________________________________________________________________11 Typische Subquery Fehlermeldung: ______________________________________________ 11 EXITSTS_____________________________________________________________________ 12 FOR ALL-Ersatz ______________________________________________________________ 12 Mehrfach SQ _________________________________________________________________ 12 SQs und Mengen ______________________________________________________________ 13 SQs und Joins _________________________________________________________________ 13 Rekursive SQs ________________________________________________________________ 14 Ausdrücke und Funktionen __________________________________________________14 WHERE i.OrdID=o.OrdID _____________________________________________________________ 14 Arithmetik ________________________________________________________________15 StringOperationen _________________________________________________________15 CharakterStrings: _____________________________________________________________ 15 Konktination: _________________________________________________________________ 15 Decode: ______________________________________________________________________ 15 Mitschrift von: Drost, Isabel/ if99wp1 Seite 2 von 23 Einführung in Datenbanken Semester: IV Substrings: ___________________________________________________________________ 15 Upper und Lower: _____________________________________________________________ 15 Intr: _________________________________________________________________________ 15 Initcap: ______________________________________________________________________ 15 Dump: _______________________________________________________________________ 16 SoundEX: ____________________________________________________________________ 16 Formatierung von Spalten_______________________________________________________ 16 Statistikfunktionen von Oracle: __________________________________________________ 17 Tabellen in Bäume wandeln _____________________________________________________ 18 SELECT prodid FROM________________________________________________________________ 19 (SELECT prodid, startdate, enddate from price where prodid=100861)___________________________ 19 Debugging ________________________________________________________________20 Reports___________________________________________________________________21 Tables erstellen und updaten _________________________________________________22 Mitschrift von: Drost, Isabel/ if99wp1 Seite 3 von 23 Einführung in Datenbanken Semester: IV Datenbanken Klausur: alles verwendbar zB. Ausarbeitung ZIELE: DBMS: Oracle-benutzen Relationale Strukturen von DB-beherrschen Linua Franca (Verkehrssprache): SQL-Syntax/Semantik lernen am Rechner (mit neuer DB) 2/ 3 Theoriefragen (praxisbezogen) Dabei interessieren nicht die Ergebnisse sondern vielmehr der Selecht selber Mittel(SE): Durchschnitt:2,5/ 3,5 Paradigmat. Einf. in SQL SQL-Syntax by doing Bsp. nachvollziehen DB-Bsp.: SCOTT/TIGER Protokollieren (Probl.,Lösg.,Syntax) Arbeit mit Oracle (nt, sql+) Doku siehe IntranetHP Aufg mögl. selbstständig Antizipation (sql selbstständig) Oracle kostenfrei über FH zu beziehen Keine Aufgabensammlung Ziel: eigene Aufgaben finden Aber: Bsp.Db verfügbar Mitschreiben via Spooling oder Cut&Paste mit Word Aufgaben: - Ausarbeiten der SeminarNotizen (KlausurVorbereitung) - Üben von SQL mit oracle (auch andere Bsp.-DB) - Zusammenhang mit Theorie herstellen (VO) Login=Novell/ Unix Paßw=(siehe Novell ;-) ) Host=RIES, ZUSE SQL – formale Sprache (hat Syntax, Semantik, Pragmatik) The only way, to learn a programming lang. Is by writing programs in it. (Kernighan ;-) ) • Prozedurale Sprache Oracle SQL+: • • Environmenteinstellungen über Options I:\oracle = pwd (shift-rechteMaustaste-openwith) Datenbankaufbauende Dateien: H:\Praktiku\Datenba\O8 START demo_bld SELECT * FROM cat; • • • • • • • • • • • demo_bld.spl, demo_drp.sql ergibt alle Einträge SQL – Befehle kommen in den Buffer, werden dort abgearbeitet R(un) wiederholt Befehl im Buffer (bei vergessenem ; - Befehl steht immernoch im Buffer) L(ist) zeigt Befehl im Buffer EDIT öffnet den SQL – Buffer im Editor SAVE xyz (xyz = Dateiname) speichert den Befehl GET xyz holt den Befehl in den SQLBuffer, der von dort via R ausgeführt werden kann. HELP hier zusätzlich installiert – oracle6, reicht meist aus Bei Error: Errormessage, Sternchen steht an der Stelle, wo der Fehler steht RollBack macht Befehle rückgängig, erst mit Ausloggen werden Änderungen permanent COMMIT macht Befehle explizit permanent SELECT *FROM cat; gibt alle Tabellennamen aus Mitschrift von: Drost, Isabel/ if99wp1 Seite 4 von 23 Einführung in Datenbanken Semester: IV Data Types • • • • • • NUMBER (entspricht INT, REAL, ... ) (die anderen können auch verwendet werden – aus Kompatibilitätsgründen mit eingebaut) CHAR(), VAR CHAR() - Char: String wird auf volle Länge mit Leerzeichen aufgefüllt, mit VARCHAR nicht - Bsp: CHAR: ‚SMITH____‘ (bei CHAR(10)) DATE (Datum, nach außen ein String, der aber auf Korrektheit des Datums geprüft wird) - Datum wird auf Korrektheit geprüft - Zeit mit integrierbar - Basierend auf Julian. Kalender - Operationen: Addition eines Monats, „Gib‘ mir nächsten Tag, der auf morgen folgt“ etc. RAW („rohe Daten“) - Binärdaten, wie Bilder etc. - Systemspezifisch und weniger kompatibel - Kaum von SQL+ unterstützt, lesen und eingeben nur via hex LONG CHAR, LONG RAW (char und raw vergrößert auf einige Gigabyte) LOB (large object binary) Multimedia sollte mit in Beleg, wens - für Multimediaanwendungen ein/ zwei Bildchen etc. - CLOB -> CHAR (an jedem System identisch) - NCLOB -> N=national languagesupport - BLOB -> binary LOB (für Bilder & Sound) - zwei Varianten: einmal einfügen als Datei oder direkt in die DB DESC emp – beschreibt den Inhalt , gibt z.B. auch den Datentyp mit aus. Konkrete Operationen Projektionen - Spaltenauswahl SELECT ename, sal, job FROM emp; SELECT DISTINCT job FROM emp; Ausgabe von Name, Gehalt, Job der Datenbank Ausgabe aller Jobs, Distinct streicht dabei alle genau gleichen Zeilen raus SELECT ename, sal, ‚Dollar‘ FRO...; Ausgabe von normalem Text in den ‚...‘ , dieser Text gilt als Überschrift SELECT ename Name,... FROM emp; temporäres Umbennen der Spalte in Name, Umschrift in Großbuchstaben, keine Leerzeichen oder Operationszeichen möglich SELECT ename „Name“, ... FROM...; Alles wird so ausgegeben, wie’s dasteht-> auch Leerzeichen und Operationszeichen möglich Bei anderen System gehört ein AS zwischen den Titel der Spalte und dem neuen Namen. 1. Aufgabe: Unterschriftenliste Name Unterschrift SCOTT ........ Lsg.: SELECT ename „Name“, ‚........‘ „Unterschrift“ Mitschrift von: Drost, Isabel/ if99wp1 Seite 5 von 23 Einführung in Datenbanken Semester: IV Selection – Auswahl von Zeilen SELECT *FROM emp WHERE deptno=30; Gib all die Leute aus, die in Departement# 30 wohnen, gibt ganze Zeilen aus SELECT 'true' " " FROM emp WHERE ename='SCOTT'; Gib true aus, wenn es einen Scott gibt SELECT * FROM emp WHERE sal>2000; Vergleichsoperatoren: <; <=; >; >=; !=; <> Wer verdient denn mehr als 2000 Dollar? SELECT * FROM emp WHERE comm>=sal; Mindestens soviel Comm wie sal SELECT * FROM emp WHERE sal>2000 and deptno=20; Mehr als 2000$ und sie leben in Departement 20 SELECT * FROM emp WHERE job='CLERK' or job='MANAGER'; Zeige alle, die entweder Manager, oder Clerk sind. SELECT *FROM emp WHERE deptno='10' and (job='CLERK' or job='MANAGER'); Wohnen in Departement 10 und haben entweder den einen, oder den anderen Job SELECT *FROM emp WHERE deptno='10' and (job!='CLERK' and job!='MANAGER'); Wohnen in Departement 10 und sind nicht Manager oder Clerk SELECT *FROM emp WHERE deptno=10 and (job<>'CLERK' and job<>'MANAGER'); Siehe oben ;-) Oder ohne Verwendung von nicht: Verwendung von De’Morgan. SELECT *FROM emp WHERE sal BETWEEN 1200 and 1400; Zwischen 1200 und 1400 (einschließlich der Grenzen) SELECT *FROM emp WHERE job in ('MANAGER','CLERK'); Job Element von {Manager, Clerk} SELECT *FROM emp WHERE job not in ('MANAGER','CLERK'); Wildcards Unix „*“ „?“ SQL „%“ „_„ Beliebig viele beliebige Zeichen Beliebiges Zeichen ename =‚S%‘ ename LIKE ‘S%‘ Suche alle die, die mit S beginnen und mit % aufhören Suche alle die, die mit S beginnen Mitschrift von: Drost, Isabel/ if99wp1 Seite 6 von 23 Einführung in Datenbanken Semester: IV Ordnung Reihenfolge bei einem normalen Select ist beliebig. ORDER BY ename ORDER BY ename DESC ORDER BY job, sal DESC, ename ORDER BY LENGHT (ename) ORDER BY 2 ordne nach ename, aufsteigend alphabet oder numerisch absteigende Anordnung mehrmals der gleiche Job->ordne absteigend nach Gehalt dann nach ename Nach der Länge sortieren Sortiere nach der 2. ausgewählten Spalte ORDER BY DECODE (Spalte, die dekodiert werden soll; Inhalt, Position; Inhalt, Position;...) Inhalt einer Spalte in anderer Reihenfolge anordnen SELECT *from emp order by decode(deptno, 30,3,20,1,10,2); Mengen Union Intersect Minus SELECT ename, job FROM emp UNION SELECT dname, loc FROM dept; Suche die Jobs, wo die deptno 10 und 20 ist: SELECT job FROM emp WHERE deptno=10 UNION SELECT job FROM emp WHERE deptno=20; Weise nach, dass union ein DISTINCT impliziert: CREATE TABLE emph AS SELECT *FROM emp; INSERT INTO emph SELECT *FROM emp; SELECT *FROM emph union SELECT *FROM emph; Erstellen einer neuen Tabelle, die wie emp aussieht, nur ohne Primary key Vereinigt die Einträge aus der neuen Tabelle, dabei werden doppelte Einträge rausgefiltert-> implizites DISTINCT SELECT *FROM emph union ALL SELECT *FROM emph;DISTINCT ausschalten Finde die Aufgabe heraus: SELECT job FROM emp WHERE deptno=10 INTERSECT ... deptno=20; Gibt die Jobs aus, die sowohl in Departement 10 als auch 20 da sind. Bei Minus, die die weder bei 10 noch 20 sind Bei gleichen Spaltennamen muß zum Ordnen die Spaltennummer angegeben werden. Mitschrift von: Drost, Isabel/ if99wp1 Seite 7 von 23 Einführung in Datenbanken Semester: IV Was passiert bei: A/B U C wird mit Klammern eindeutig, sonst von oben nach unten Gleichheit von Mengen: Wenn zwei Tabellen gleich sind, kann ich ja eine wegschmeißen. Mathemat. Definition ist folgende: A Teilmenge von B und B Teilmenge von A. Ausgedrückt mit Minus: A\B UNION B\A = 0. (SELECT *FROM emph MINUS SELECT *FROM emp)UNION(SELECT *FROM emp MINUS SELECT *FROM emph); DELETE emph WHERE ename='SMITH'; (SELECT *FROM emph MINUS SELECT *FROM emp)UNION(SELECT *FROM emp MINUS SELECT *FROM emph); - bringt die vorher gelöschte Zeile ans Tageslicht, die jetzt nur noch in emp enthalten ist Nullwerte Werte, die unbekannt sind, sind nicht gleich NULL ! SELECT *FROM emp WHERE comm=NULL; no rows selected Erklärung: Vergleiche einen Wert, den Du angucken kannst und vergleiche ihn mit dem Fakt, dass er nicht da ist. Ist semantischer Blödsinn. SELECT *FROM emp WHERE comm IS NULL; liefert hier die richtige Ausgabe. Wenn wir all die wollen, die nicht Null sind: SELECT *FROM emp WHERE comm IS NOT NULL; Tautologien: SELECT ... WHERE comm=comm; Dürfte immer wahr sein, Tautologie. Gibt aber nicht alle 14 Zeilen aus: die, die nicht definiert sind, werden nicht ausgegeben. SELECT *FROM emp WHERE comm>1000 OR comm<=1000; (siehe oben) Sowas kann notwendig sein, wird vom OracleSystem aber nicht wirklich unterstützt, da es anscheinend eine dreiwertige Logik verwendet. Ausprobieren hilft gegen’s auf die Nase fliegen. Join Aufteilung von einer Tabelle in mehrere, um Redundanz zu vermeiden. Z.B. Einführung einer Nummer für’s Department und Extratabelle für die Departmentnamen. SELECT ename, loc FROM emp, dept; Bringt alle Jobs kombiniert mit allen Dept# SELECT ename, loc FROM emp, dept WHERE deptno=deptno; Bringt Fehler: mehrdeutig. SELECT ename, loc FROM emp, dept WHERE emp.deptno=dept.deptno; Entfernt Mehrdeutigkeit, da die Tabellen direkt angesprochen werden. SELECT ename, loc, dept.deptno FROM emp, dept WHERE emp.deptno=dept.deptno Gibt auch die Nummer selber mit aus. SELECT e.deptno FROM emp e, dept d; Mitschrift von: Drost, Isabel/ if99wp1 Bei langen Tabellennamen ist deren Umbenennung möglich. Seite 8 von 23 Einführung in Datenbanken Semester: IV SELECT emp.*, loc FROM emp, dept WHERE emp.deptno=dept.deptno; Dann ist aber der Zugriff über emp.x nicht mehr möglich. Gibt alle Zeilen aus emp aus und loc aus dept. Allerdings kombiniert er nur sinnvoll (nur die, wo die Departmentnummern übereinstimmen.) Läßt man die join Bedingung weg, ergibt dies ein karthesisches Produkt. Vorgeschlagene Reihenfolge für den Selectaufbau: 1. 2. 3. SELECT SELECT SELECT xxx FROM xxx FROM xxx FROM xxx WHERE xxx WHERE xxx Reihenfolge der angegebenen kann für die Performance von Relevanz sein. Ein gutes System sollte hier optimieren und die ideale Reihenfolge verwenden. JOINs dieser Art („=“ in der JOINBedingung hinter dem WHERE) heißen Equi-Joins. Semi-Joins hingegen verwenden die Tabellen, zeigen aber von der zweiten Tabelle nichts an. (häh? Wie jetzt?) Ach, so: nur was aus der ersten Tabelle und nix aus der zweiten Tabelle. Dazu wird erstmal das karthesische Produkt entfernt (joinBedinung). Hier wird auch der Angestellte nicht doppelt ausgegeben, dadurch dass DISTINCT angegeben wurde. SELECT DISTINCT ename FROM emp, customer WHERE (emp.empno=customer.repid) Outer Join Ziel: Gib alle Zeilen zweier Tabellen aus. Dabei soll es möglich sein, Zeilen auszugeben, die nach der joinBedingung kein Pendant haben. Z.B. gibt es mehr Departments als Angestellte. Ich will also alle Departments und dazu alle Angestellten. SELECT *FROM emp,dept WHERE emp.deptno(+)=dept.deptno Select dname,ename,name from emp,dept,customer where dept.deptno=emp.deptno(+) and emp.empno=customer.repid(+) Wählt alle Departments aus, dazu alle passenden Angestellten und dazu wiederum alle Kunden. Schwierigkeit hierbei ist, dass es Departments ohne Angestellte gibt, dass es Angestellte ohne Kunden gibt, die aber alle ausgegeben werden sollen. Deshalb der (+) (outer Join) – Operator. Dieser gibt auch alle die Einträge einer Tabelle aus, die der passenden Tabelle kein Pendant haben. INSERT into emp (empno,ename,deptno) Values (7,'Bond',NULL); Einfügen neuer Werte – geht nicht, da deptno nicht null sein darf. ORA-01400: cannot insert NULL into ("IDROST"."EMP"."DEPTNO") INSERT into emp (empno,ename,deptno) Values (7,'Bond',70); Geht nicht, da es keinen ParentKey in der anderen Tabelle gibt. Somit kann es nicht passieren, dass z.B. in einer Bibliothek ein Buch von jemandem ausgeliehen wird, den es gar nicht gibt (wenn ich den, der es ausgeliehen hat, über den PrimaryKey identifiziere, muß es diesen ja auch geben, sonst kann es mir ja passieren, dass ich jemandem ein Buch verliehen habe, den es gar nicht gibt...) ORA-02291: integrity constraint (IDROST.EMP_FK) violated - parent key not found Mitschrift von: Drost, Isabel/ if99wp1 Seite 9 von 23 Einführung in Datenbanken Semester: IV Outer emp U Equi U Outer(dept) Wähle alle enames aus emp und alle dnames aus dept! Select ename, dname from emp, dept where dept.deptno=emp.deptno(+) union Select ename, dname from emp, dept where dept.deptno(+)=emp.deptno; AutoJoin Suche emp, die mehr als ihr Chef verdienen! (mgr ist # vom boss) select e.ename, e.sal, b.ename,b.sal from emp e,emp b where e.mgr=b.empno and e.sal>b.sal Läuft mit einem Join einer Tabelle auf sich selber. TetaJoin Θ Statt „=“ wird <;>; ... verwendet. 1. Suche emp, die mehr als Johns verdienen! select e.ename, e.sal, j.ename, j.sal from emp e, emp j where e.sal>j.sal and j.ename='JONES' BETWEEN – Operator Suche ename mit Gehaltsklasse! Das Karthesische Produkt Wir haben Ziffern von 0-9 und wollen nun alle Dezimalzahlen. Lösung: Verwendung des krathesischen Produktes, angewendet auf eine Tabelle mit den 10 Dezimalzahlen von 0 bis 9. Verwende zur Programmierung von Interfaces zu SQL/ Oracle am besten Java – noch am meisten unterstützt! CREATE TABLE digit (d NUMBER); INSERT INTO digit VALUES (0); ... INSERT INTO digit VALUES (9); SELECT e.d +10*z.d FROM digit e, digit z; Mitschrift von: Drost, Isabel/ if99wp1 Seite 10 von 23 Einführung in Datenbanken Semester: IV Subquery SELECT *FROM emp WHERE sal>(SELECT sal FROM emp WHERE ename='JONES'); Mainquery Subqurery Wähle all die aus, bei denen das Gehalt größer ist, als das von Jones. Das von Jones wird dabei in der Subquery erst ermittelt. SELECT *FROM dept WHERE deptno NOT IN (SELECT deptno FROM emp); Wähle die Abteilung, die keine Beschäftigten hat. SELECT d.dname, e.ename FROM emp e, dept d WHERE e.deptno=d.deptno UNION SELECT d.dname, NULL FROM dept d WHERE d.deptno NOT IN (SELECT deptno FROM emp) Typische Subquery Fehlermeldung: SELECT *FROM emp WHERE sal>(SELECT sal FROM emp WHERE deptno=30); Hat zur Folge: ORA-01427: single-row subquery returns more than one row SELECT *FROM emp WHERE sal>ANY(SELECT sal FROM emp WHERE deptno=30); (nimm einen x-beliebigen aus department 30, dabei kommen auch einige aus department 30 mit) SELECT *FROM emp WHERE sal>ALL(SELECT sal FROM emp WHERE deptno=30); (nimm die, die mehr verdienen als ALLE in department 30) • Statt dem ALL könnte man auch angeben: • Anstelle von Any könnte man auch das Minimum raussuchen: (SELECT MAX(sal) FROM emp WHERE deptno=30); (SELECT MIN(sal) FROM emp WHERE deptno=30); SELECT ename, job, deptno FROM emp WHERE job IN (SELECT job FROM emp WHERE deptno=30); Wählt all die jobs mit departmentnumber aus, die in department 30 vorkommen. SELECT job, deptno FROM emp WHERE job NOT IN (SELECT job FROM emp WHERE deptno=30) Wählt all die jobs, die nicht in department 30 vorkommen. • • • IN NOT IN NOT IN = ANY != ALL = NOT ANY Mitschrift von: Drost, Isabel/ if99wp1 Seite 11 von 23 Einführung in Datenbanken Semester: IV EXITSTS SELECT *FROM dept WHERE EXISTS (SELECT *FROM emp WHERE dept.deptno=emp.deptno) Gib alle Departments aus, zu denen auch ein employee <spc?> gehört. Exists vergleichbar mit dem „es gibt“ aus der Logik. „Für alle gilt“ lässt sich folgendermaßen darstellen: „Es gibt keinen, für den es nicht gilt“. FOR ALL-Ersatz SELECT dname FROM dept WHERE EXISTS (SELECT *FROM emp WHERE emp.deptno=dept.deptno AND NOT EXISTS (SELECT *FROM emp WHERE comm>sal AND dept.deptno=emp.deptno )) Suche Depts, in denen niemand mehr comm als sal erhält! Suche alle departments raus, bei denen es folgendes gibt: Es GIBT Angestellte Es gibt KEINE Angestellte, die mehr comm haben als sal haben. Wir betrachten nur das gewählte Departement, nicht die ganze Firma. Wir müssen das so verdreht machen, da es kein „Es gilt für alle“ gibt. Eine Negierung ergibt somit: Es gibt niemanden, für den das Gegenteil gilt. SELECT dname FROM dept WHERE EXISTS (SELECT *FROM emp WHERE emp.deptno=dept.deptno AND NOT EXISTS (SELECT *FROM emp WHERE hiredate>=TO_DATE('01-JAN-1982','DD-MON-YYYY') AND dept.deptno=emp.deptno )) Suche Depts, deren emps alle vor 82 eingestellt wurden. (Beziehungsweise all die Depts, deren emps NICHT nach ‘82 eingestellt wurden.) SELECT dname FROM dept WHERE EXISTS (SELECT *FROM emp WHERE emp.deptno=dept.deptno) MINUS SELECT dname FROM dept WHERE EXISTS (SELECT *FROM emp WHERE hiredate>=TO_DATE('01-JAN-1982','DD-MON-YYYY') AND dept.deptno=emp.deptno ) Das gleiche mit Mengenlehre... (Alle die Zeilen, die emps enthalten, minus die Zeilen, wo das Einstellungsdatum nicht stimmt.) Mehrfach SQ SELECT ename FROM emp WHERE (sal,job)= (SELECT sal,job FROM emp WHERE ename='FORD') All die, die mit dem gleichen Job das gleiche verdienen wie Ford. Mitschrift von: Drost, Isabel/ if99wp1 Seite 12 von 23 Einführung in Datenbanken Semester: IV SQs und Mengen SELECT ename FROM emp WHERE job=(SELECT job FROM emp WHERE ename='JONES') OR sal>(SELECT sal FROM emp WHERE ename='FORD') Job(Jones) Sal(Ford) SELECT ename FROM emp WHERE job=(SELECT job FROM emp WHERE ename='JONES') UNION SELECT ename FROM emp WHERE sal>(SELECT sal FROM emp WHERE ename='FORD') Alle die, die entweder den gleichen job oder das gleiche Gehalt wie Jones bzw. Ford haben. SELECT * FROM emp WHERE job IN (SELECT job FROM emp WHERE deptno=(SELECT deptno FROM dept WHERE dname='SALES')) Alle die, die einen Job haben, der auch im Salesdepartment vorkommt. SQs und Joins SELECT *FROM emp, dept WHERE emp.deptno=dept.deptno AND loc='CHICAGO' AND job= (SELECT job FROM emp WHERE ename='ALLEN') Loc(CHICAGO) UND Join SELECT *FROM emp, dept WHERE emp.deptno=dept.deptno AND loc='CHICAGO' Job(ALLEN) SQ AND job=( SELECT job FROM emp WHERE ename='ALLEN') Join, der komplett mit einer SQ austauschbar ist: Semijoin. (Da ja die Zeilen der SQ nicht angezeigt sondern nur ausgewertet werden können... Mitschrift von: Drost, Isabel/ if99wp1 Seite 13 von 23 Einführung in Datenbanken Semester: IV Rekursive SQs SELECT dname, ename, job FROM dept, hole aus dept und der temporären Tabelle best. Sachen raus (SELECT ename, job, deptno FROM emp die temporäre Tabelle aus dem Select heraus WHERE TO_CHAR (hiredate,'yy')>'81') emp_v WHERE dept.deptno=emp_v.deptno ; Wann kann eine SQ durch einen Join ersetzt werden? Select *From emp Where sal> (Select sal From emp Where ename='JONES') Select e.* From emp e, emp r Where e.sal>r.sal And r.ename='JONES' Semijoins lassen sich als SQs darstellen. Joins sind i.d.R. mächtiger als SQs. Somit dürften sich alle SQs als Join darstellen lassen – als Semijoin. Tlw. lassen sich SQ schneller erstellen als Joins. Ausdrücke und Funktionen Select ename, sal+comm From emp Where job='SALESPERSON'; Where sal>comm*0,25 Order by Comm/sal Sowohl in Selects als auch in WhereKlauseln und OrderByKlauseln sind mathematische Ausdrücke möglich. Probleme gibt es nur, wenn in einem Summanden NULL drin steht. Lösung ist die NVL Funktion. Bei NUMBER gibt es dabei kein Problem. Bei allen anderen Datentypen muß ich direkt den Datentyp angeben: NVL(TO_CHAR ‚nix da‘) Select ename, sal, comm, sal+NVL(comm,0) From emp; Wenn in comm ein nullValue steht, schreibe dafür die richtige – mathemat. Null und addiere die! Select ename, sal, NVL(TO_CHAR(comm),'nix da') From emp; Diverse Joins in einem Select: SELECT i.OrdID, i.ItemID, i.ActualPrice, pr.StdPrice FROM Ord o, Item i, Product p, Price pr WHERE i.OrdID=o.OrdID AND i.ProdID=p.ProdID AND p.ProdID=pr.ProdID AND orderdate BETWEEN pr.startdate AND NVL(enddate,SYSDATE) OrdID ItemID ActualPrice StdPrice Item Product OrdID ProdID ActualPrice ProdID Ord Price OrdID Mitschrift von: Drost, Isabel/ if99wp1 ProdID StdPrice Startdate Enddate Seite 14 von 23 Einführung in Datenbanken Semester: IV Arithmetik ROUND TRUNC POWER (Basis, Exponent) SQRT SIN etc. Berechnungen mit der Tabelle dual ausführen. (Tabelle mit nur einer Zeile.) StringOperationen CharakterStrings: SELECT CHR(100) ... SELECT ASCII(‚d‘)... Konktination: SELECT ename||‘is a‘||job... Decode: select job, Decode(job,'PRESIDENT',5,'CLERK',1,'MANAGER',3,2) class From emp Update mittels Decode: Update emp set sal=sal* decode(deptno,10,1.1, 20,1.05, 30,1) Dies ließe sich auch mit zwei Updates machen. So isses schlicht kürzer. Substrings: select substr(dname,2,5) from dept; Upper und Lower: Select ename, UPPER(ename), Lower(ename) From emp Where Lower(ename)=Lower('Scott'); Intr: Select instr(job,'Person') from emp; (Soundsooft kommt der angegebene String in dem anderen string vor.) Initcap: Select initcap(ename||'is a'||job) from emp; Erster Buchstabe jedes Wortes wird grossgeschrieben, alle anderen klein. Mitschrift von: Drost, Isabel/ if99wp1 Seite 15 von 23 Einführung in Datenbanken Semester: IV Dump: Gibt die interne Darstellung des Datums aus: Typ=12 Len=7: 119,181,11,17,1,1,1 Typ=12 Len=7: 119,181,4,2,1,1,1 Typ=12 Len=7: 119,181,5,1,1,1,1 Typ=12 Len=7: 119,181,6,9,1,1,1 . . . SoundEX: Ich weiß, wie’s klingt, nur mit der Rechtschreibung habsch so meine Probleme... SELECT ename, Soundex(ename) from emp where soundex(ename)=soundex('Smyth'); Bringt den enthaltenen Smith. (genauso bei Schmied, Schmitt etc.) Der SoundexWert liegt bei S530. Formatierung von Spalten Lpad/ Rpad Column x Heading ‚Histogramm | 0 ... 1000 ... 200 ... 5000‘ Column x Format A50 Justify c Select ename, sal, LPAD(' ',ROUND(sal/100),'$') x From emp ; Select job, LTRIM(job, 'SALE') From emp ; alle Zeichen da drin, werden von links beginnend weggeschnitten, die in den Hochkommas stehen, kommt ein unbekanntes, wird die Ersetzung abgebrochen Date: select hiredate, TO_CHAR( hiredate,'DAY.MONTH.DD') from emp gibt Tag und Monat in Worten aus select hiredate, TO_CHAR( hiredate,'"The"ddspth "Day of" MONTH, "The Year of Our Lord" YYYY AD') from emp ergibt: HIREDATE TO_CHAR(HIREDATE,'"THE"DDSPTH"DAYOF"MONTH,"THEYEAROFOURLORD"YYYYAD' -------- ------------------------------------------------------------------17.11.81 Theseventeenth Day of NOVEMBER , The Year of Our Lord 1981 N.CHR. 02.04.81 Thesecond Day of APRIL , The Year of Our Lord 1981 N.CHR. 01.05.81 Thefirst Day of MAI , The Year of Our Lord 1981 N.CHR. 09.06.81 Theninth Day of JUNI , The Year of Our Lord 1981 N.CHR. 20.02.81 Thetwentieth Day of FEBRUAR , The Year of Our Lord 1981 N.CHR. Mitschrift von: Drost, Isabel/ if99wp1 Seite 16 von 23 Einführung in Datenbanken Semester: IV Zeitformatierung: SELECT TO_CHAR( SYSDATE,'HH:MI:SS') FROM dual Zeitformat lässt sich permanent auch am Server, am Client und in der Session ändern. Sessionbeispiel (einzig für uns Studis mögliche Variante): Ergibt: TO_CHAR( -------10:22:59 ALTER SESSION set nls_date_format='"Today''s date is" dd/mm/yy' ; Ergibt als Formatierung: SYSDATE -----------------------Today's date is 08/05/01 Rechnen mit dem Datum ist ebenfalls möglich: SELECT NEXT_DAY(SYSDATE,'SONNTAG') FROM dual; Sucht den nächsten Sonntag raus Ergibt: Today's date is 13/05/01 (und heute is der 8.5.2001 – he nur noch ... Select (25-8) from dual ; ... 17 Tage ... bis zum 25 ... *freu*) SELECT LEAST('21-JAN-77','21-DEZ-77') FROM dual; Sollte das Kleinere von beiden raussuchen Ergibt aber den Dezember. Erfolgt deshalb, weil das ganze als String betrachtet wird und das D nunmal vor dem J im Alphabet kommt... Um es als Datum zu betrachten fehlt die (blaue) To_Date-Funktion. SELECT LEAST(TO_DATE('21-JAN-77','DD-MON-YY'),TO_DATE('21-DEZ-77','DD-MON-YY')) FROM dual; SELECT TO_DATE('25-MAI-2001','DD-MON-YYYY')-SYSDATE from dual; Hee – noch genau 16,553426 Tage, bis ich Thilo wiedersehe... Statistikfunktionen von Oracle: MIN(SAL) SUM(SAL) AVG(COMM) -----------------------1300 8750 SELECT MIN(sal), SUM(sal),AVG(comm) From emp where deptno=10; Suche den emp mit dem maximalen Gehalt heraus! SELECT ename,sal from emp where sal=(Select Max(sal) from emp); ENAME SAL ---------- --------KING 5000 Wieviel Leute sind in Departement 30? SELECT COUNT(ename) From emp Where deptno=30 Ergibt 6. Nimm keine Spalte, die Nullwerte enthält, es sei denn natürlich, du willst die Nullwerte zählen. Wieviele verschieden Jobs gibt es in der Firma? Select count(distinct job) from emp; Select ename, Max(sal) from emp Group by ename SELECT MAX(sal), COUNT(ename), deptno FROM emp GROUP BY deptno; Mitschrift von: Drost, Isabel/ if99wp1 Damit is zwar der Fehler von ohne wech, dennoch kriege ich logischerweise nicht das Maximale Gehalt der Firma. Ergibt pro Abteilung die Mitarbeiteranzahl und das maximale Gehalt davon. Seite 17 von 23 Einführung in Datenbanken Semester: IV SELECT MAX(sal), COUNT(ename),job, deptno FROM emp GROUP BY job, deptno DEPTNO --------10 10 10 10 20 20 20 30 30 30 SELECT dept.deptno, dname, job, max(sal) FROM emp, dept WHERE dept.deptno=emp.deptno GROUP BY dept.deptno, dname, job Maximales Gehalt pro Department, pro Job SELECT max(sal), job from emp group by job having count(*)>1; Reihenfolge im GroupBy wirkt sich nur auf die Ausgabereihenfolge aus, nicht auf’s Ergebnis. GroubBy wirkt dabei wie ein aufsteigendes OrderBy. DNAME -------------- ---ACCOUNTING ACCOUNTING ACCOUNTING ACCOUNTING RESEARCH RESEARCH RESEARCH SALES SALES SALES MAX(SAL) --------1300 2450 5000 ANALYST CLERK MANAGER CLERK MANAGER SALESPERSON 3000 1100 2975 950 2850 1600 MAX(SAL) --------- ----3000 1300 2975 1600 Nimm Dir das maximale Gehalt vor, berechne es pro Jobgruppe und gib es nur von den Gruppen aus, die mehr als einen beinhalten, der diesen Job hat. SELECT dept.deptno, dname, avg(NVL(sal,0)) FROM emp, dept WHERE dept.deptno=emp.deptno(+) GROUP BY dept.deptno, dname ; JOB ------CLERK MANAGER PRESIDENT JOB -----ANALYST CLERK MANAGER SALESPERSON Gib dname, department und DEPTNO DNAME AVG(NVL(SAL,0)) AVG(sal) aus. Nimm auch ------ ---------- --------------Operators mit und gib deren 10 ACCOUNTING 2916,6667 20 RESEARCH 2175 sal mit „0“ aus! 30 SALES 1566,6667 40 OPERATIONS 0 Tabellen in Bäume wandeln SELECT LEVEL, ename, empno,mgr FROM emp CONNECT BY mgr=PRIOR empno START WITH ename='KING' ; Erstelle eine Rangliste der Firma, aus der Du einen Baum konstruieren kannst! SELECT LPAD(' ',(LEVEL-1)*3)||ename FROM emp CONNECT BY mgr=PRIOR empno START WITH ename='KING' ; Rücke zusätzlich ein! SELECT LPAD(' ',(LEVEL-1)*3)||ename FROM emp CONNECT BY empno=PRIOR mgr START WITH ename='SMITH' ; Wer steht über Smith? Mitschrift von: Drost, Isabel/ if99wp1 1 2 3 4 3 4 2 KING JONES SCOTT ADAMS FORD SMITH BLAKE 7839 7566 7788 7876 7902 7369 7698 7839 7566 7788 7566 7902 7839 KING JONES SCOTT ADAMS FORD SMITH BLAKE ALLEN WARD MARTIN TURNER JAMES CLARK MILLER SMITH FORD JONES KING Seite 18 von 23 Einführung in Datenbanken Semester: IV Reihenfolge bei einem zusätzlichen Where: From Where Connect Start Order SELECT LPAD(' ',(LEVEL-1)*3)||ename FROM emp WHERE ename!='SCOTT' CONNECT BY mgr=PRIOR empno START WITH ename='KING' Suche die Reihenfolge raus, lasse Smith raus. Dabei baut Oracle erst die gesamte Tabelle auf, dann nimmt es Smith raus – sonst gängen ja die drunter verloren. KING JONES ADAMS FORD SMITH BLAKE ALLEN WARD MARTIN TURNER JAMES CLARK MILLER select prodid, startdate, enddate from price where prodid=100861; Nimmt Zeilen raus, in denen die ProduktID nicht mit dem hier übereinstimmt. Haken ist, wenn ich wirklich nur die Hierarchie dieses Produkte betrachten will, wie hier. Um diese Unterzweige zu erschlagen, muß ich entweder eine neue Pseudotabelle, View oder rekursive SQ verwenden: SELECT prodid FROM (SELECT prodid, startdate, enddate from price where prodid=100861) CONNECT BY startdate=PRIOR enddate+1 START WITH startdate=TO_DATE('01.01.1985','DD,MM,YYYY') Zweite Möglichkeit: Select ... Connect by ... AND ename!=‘JONES‘ Wirft auch alle Unterbäume von Jones mit weg. Select ename,level from emp where level=2 connect by mgr=prior empno start with ename='KING' Select level, AVG(sal) from emp connect by mgr=prior empno start with ename='KING' group by level; Suche die Abteilungsleiter – die auf Level 2 – heraus! Gib pro Level das durchschnittliche Gehalt aus! Join mit Connect By etc is nich soo einfach: zum Join gehört eine JoinBedinung und die steht in der WhereKlausel, die wiederum zuletzt drankommt. Also muß ich den Join wie oben wieder in einer SQ verpacken! Select level, ename, job from emp connect by mgr=prior empno start with empno IN (Select empno from emp where job='MANAGER') ; Mitschrift von: Drost, Isabel/ if99wp1 Baue die Tabelle vom zweiten Level aus auf – also ab den Managern! Seite 19 von 23 Einführung in Datenbanken Semester: IV DELETE emp where empno IN (Select empno from emp connect by mgr=PRIOR empno start with ename='JONES'); Lösche Jones und seine Mannen! Debugging Zum Beispiel: gib die Rabatte aus, die die Mitarbeiter gegeben haben ename – avg/ max/ (StdPrice-ActualPrice) Debugging in der Datenbänkerei besteht z.B. darin, Daten zu finden, die semantisch inkorrekt sind. Bezogen auf das Beispiel heißt das: OrdID – ItemID – stdprice-actualprice, um zu testen, dass jeweils actualprice unter dem stdprice sind. Dabei muß ich soviele Zeilen erwarten, wie Items (bestellte Artikel) da sind =>64. Dies ist auf Fehler in den Tabellen zurückzuführen, z.B. gibt es Produkte, die unter dem Minimalpreis oder über dem Standardpreis verkauft worden sind. Die eine Zeile, die unter den Tisch fällt liegt daran, dass die Bestellung am 1.5.86 verkauft wurde, der Preis aber erst ab Mitte Mai feststand. Select dazu: select itemid, prodid from item minus ( select itemid, item.prodid from item, price, ord where item.prodid=price.prodid and item.ordid=ord.ordid and orderdate between price.startdate and NVL(enddate,sysdate) ) (ergibt die Zeile, die mir fehlt, in Item bekomme ich jetzt über die prodid und die itemid die richtige ordid heraus sowie das Datum, ab dem ein Preis feststand. In Ord bekomme ich über die Ordid heraus, dass die Bestellung abgewickelt wurde, bevor der Preis feststand. > select *from item where prodid=200376; ORDID ITEMID PRODID ACTUALPRICE ------ --------- --------- ----------- --------- --------601 1 200376 2,4 1 2,4 613 4 200376 2,2 200 440 620 2 200376 2,4 1000 2400 616 5 200376 2,4 10 24 619 2 200376 2,4 100 240 617 9 200376 2,4 200 480 QTY ITEMTOT ows selected. > select *from price where prodid=200376; PRODID STDPRICE MINPRICE STARTDAT ENDDATE ------ --------- --------- -------- -------200376 2,4 1,75 15.11.86 > select *from ord where ordid=601; ORDID ORDERDAT C CUSTID SHIPDATE ------ -------- - --------- -------- --------Mitschrift von: Drost, Isabel/ if99wp1 TOTAL Seite 20 von 23 Einführung in Datenbanken Semester: IV 601 01.05.86 A 106 30.05.86 2,4 Dies läßt vermuten, dass in den Tabellen noch weitere Fehler sind. Z.B., dass teils der bezahlte Preis über dem Standardpreis liegt. SQL> r STDPRICE MINPRICE ACTUALPRICE --------- --------- ----------1 select stdprice, minprice, actualprice from price, item, ord 35 28 44 2 where item.prodid=price.prodid 35 28 56 3 and ord.ordid=item.ordid 45 36 45,11 2,8 2,4 45 4 and orderdate between startdate and Nvl(enddate, sysdate) 5* and stdprice<actualprice Oder der bezahlte unter dem minimalpreis: SQL> r 1 select stdprice, minprice, actualprice from price, item, ord 2 where item.prodid=price.prodid 3 and ord.ordid=item.ordid 4 and orderdate between startdate and Nvl(enddate, sysdate) 5* and actualprice<minprice STDPRICE MINPRICE ACTUALPRICE --------- --------- ----------12,5 9,4 9 45 36 35 Reports monatliche Ausgaben – packe monatliche Selects in ein Script. Verwendung von Column möglich: column Column-name Heading ‚employee|Name‘ format A50; column column-name off; schaltet die Formatierung wieder aus column column-name on; schaltet die Formatierung wieder an column; gibt alle definierten Spalten aus Weitere Formate (bei Zahlen): 999.99 – runde auf nachkommastellen 999V99 – verstecke den Dezimalpunkt 9,999 B999 – macht aus einer Null ein Blank 09999 – führende Null mit ausgeben 999M1 – Minus am Ende ausgeben Dies finde ich auch in der SQL+ - Referenz im Netz! SQL> select deptno, ename, sal from emp order by deptno; DEPTNO ENAME SAL --------- ---------- --------10 KING 5000 CLARK 2450 MILLER 1300 20 JONES FORD ADAMS SCOTT SMITH 2975 3000 1100 3000 800 30 BLAKE JAMES TURNER ALLEN WARD 2850 950 1500 1600 1250 Mitschrift von: Drost, Isabel/ if99wp1 Nützlich ist das break: break on deptno skip 2; (zeigt dep 10 etc. einmal an, dann wird sie unterdrückt) Zwischen die Ausgaben kommen immer zwei Leerzeilen: Seite 21 von 23 Einführung in Datenbanken Semester: IV break on dname skip 0 on loc skip 0 on deptno; SQL> r 1 select dname, loc, ename, dept.deptno from dept,emp 2 where dept.deptno=emp.deptno 3* order by dname DNAME LOC ENAME DEPTNO -------------- ------------- ---------- --------ACCOUNTING NEW YORK KING 10 CLARK MILLER RESEARCH DALLAS JONES 20 FORD ADAMS SCOTT SMITH SALES CHICAGO BLAKE 30 JAMES TURNER ALLEN WARD MARTIN clear break schmeißt die breaks weg Tables erstellen und updaten Projektnummer|Projektname|Budget 101 alpha 250000 102 beta 103 gamma create table project (pno number primary Key, pname varchar(10), budget number); insert into project values (101,'Alpha',250000); insert into project values (102,'Beta',Null); insert into project (pname, pno) values ('gamma',103); update project set budget=100000 where pno=102; SQL> r 1* select pno, rownum, rowid from project PNO ROWNUM ROWID --------- --------- -----------------101 1 AAAFl5AACAAAFVJAAA 102 2 AAAFl5AACAAAFVJAAB 103 3 AAAFl5AACAAAFVJAAC Rownum=Zeilennummer, interessant vor allem, wenn ich laufende Werte verändern will: update project set pno=rownum; RowId=physikalische Adresse der Zeile innerhalb von Oracle update project set pno=pno+1; Problem dabei ist, dass es sich hierbei um einen PrimaryKey handelt. Zwischenrein gibt es also übereinstimmende Schlüsselwerte. Bei rein objektorientierten Ansätzen ist dies überhaupt nicht erlaubt, da darf ich die Keys nicht verändern. Wenn ich diese Möglichkeit nicht hätte, das so abzuschicken, könnte ich zwischenzeitlich den Primarykey lahmlegen. Ansonsten,wenn ich weiß, der höchste ist 1000, na dann addiere ich halt erstmal 1001 und ziehe dann 1000 wieder ab ... delete löscht Zeilen drop table project löscht die Tabelle. Mitschrift von: Drost, Isabel/ if99wp1 Seite 22 von 23 Einführung in Datenbanken Semester: IV 2. Select Name, NVL(to_char(Beruf),'nix da'), Gehalt From Mitarb where NVL(to_char(Beruf),'nix da')= (Select NVL(to_char(Beruf),'nix da') from Mitarb where Name='Walter') and Gehalt=(Select Gehalt from Mitarb Where Name='Walter') 3. Select Pname, Count(Pname) From ( Select Pname, pr.PNR from Projekt pr, Mitpro mi, Mitarb arb Where pr.PNR=mi.pnr and mi.mnr=arb.mnr ) group by Pname having Count(Pname)>7 4. Select Name from Mitarb Where Zimnr= (Select Zimnr From Mitarb Where Name='Froschmann') and Mitarb.Abtnr= (Select Abtnr From Abteilung Where Abtbez='Rechenzentrum') 5. select Zimnr, count(zimnr) From Mitarb Group by Zimnr having count(zimnr)>2 6. Select Name, Abteilung.Abtnr, Abtbez, Pnr, Pname Pleiter from Abteilung, Mitarb, Projekt Where Abteilung.aleiter=Mitarb.mnr and Abteilung.aleiter=Projekt.pleiter 7. Select Name, mnr, aleiter, Abteilung.Abtnr, gehalt, 'A Abteilung, Mitarb, Projekt Where Abteilung.aleiter=Mitarb.mnr Union Select Name, mnr, aleiter, Abteilung.Abtnr, gehalt, 'P Abteilung, Mitarb, Projekt Where Mitarb.mnr=Projekt.pleiter Minus Select Name, mnr, aleiter, Abteilung.Abtnr, gehalt, 'P Abteilung, Mitarb, Projekt Where Mitarb.mnr=Projekt.pleiter and Mitarb.mnr=Abteilung.aleiter order by name ' "code" from ' "code" from ' "code" from 8. Select sum(Gehalt) "Gehaltsumme", count(name) "Anz_Mitarbeiter", avg(Gehalt) "Durchschn_Gehalt" from Mitarb where Gehalt< (Select avg(Gehalt) from Mitarb) 9. Select Gehalt, name, vorname from Mitarb where Gehalt> (Select avg(Gehalt) from Mitarb) order by name Mitschrift von: Drost, Isabel/ if99wp1 Seite 23 von 23