Betrifft: Oracle 9i New Features – SQL und PL/SQL Autor: Christine Hansen ([email protected]) Art der Info: Technische Background Info – Teil 2 (April 2002) Quelle: Aus dem NF9i-Kurs und NF9i-Techno-Circle der Trivadis Einleitung Im ersten Teil haben wir von den neuen Features in Oracle 9i die SQL-Funtkionen betrachtet. In diesem zweiten Teil werden wir uns nun mit den Neuerungen im Bereich der ANSI kompatiblen Join-Syntax und dem Sub-Query Factoring beschäftigen. ANSI kompatible Join-Syntax Oracle unterstützt mit der Version 9i jetzt auch die ANSI-SQL-Syntax 99. Es stehen dabei folgende Join-Typen zur Verfügung: Cross Join Natural Join Join mit USING-Klausel Join mit ON-Klausel Outer-Join (Left, Right und Full) Diese Neuerungen erleichtern nicht nur den Umstieg von und zu anderen Datenbanken, sie verbessern zusätzlich, durch die Trennung von Join- und WHERE-Bedingung, die Lesbarkeit des Codes. Cross Join Der Cross Join entspricht dem kartesische Produkt von zwei oder mehr ohne JoinBedingung selektierten Tabellen. SELECT ename, d.deptno, dname FROM emp CROSS JOIN dept d Es ist zu bemerken, dass eine kartesisches Produkt zweier Tabellen äußerst selten in der Praxis benötigt wird. Durch die neue Syntax hat der Anwender den Vorteil hat, dass er auf einen Blick erkennen kann, dass mit dem Statement wirklich ein Cross Join gemeint ist und nicht einfach nur die WHERE-Clause vergessen wurde. Natural Join Der Natural-Join basiert auf den Tabellenspalten mit gleichem Namen und Datentyp. Bei dieser Verknüpfung werden automatisch alle Spalten mit gleichem Namen und Datentyp in die Join-Bedingung eingebunden. Die SELECT * - Syntax liefert allerdings Spalten nicht doppelt zurück. SELECT ename, deptno, dname FROM emp NATURAL JOIN dept Nicht zulässig ist die Qualifizierung von Spaltennamen mit Tabellennamen oder Aliasen: SQL> SELECT ename, d.deptno, dname 2 FROM emp NATURAL JOIN dept d; SELECT ename, d.deptno, dname * ERROR at line 1: ORA-25155: column used in NATURAL join cannot have qualifier Wie gewohnt kann nach der Join-Klausel eine oder mehrere WHERE-Bedingungen folgen: SQL> SELECT ename, deptno, dname 2 FROM emp NATURAL JOIN dept 3 WHERE deptno = 10; ENAME DEPTNO DNAME ---------- --------- -------------CLARK 10 ACCOUNTING KING 10 ACCOUNTING MILLER 10 ACCOUNTING Join mit USING-Klausel Während beim Natural Join alle übereinstimmenden Spalten zweier Tabellen zur Verknüpfung verwendet werden, kann über die USING-Klausel explizit eine bestimmte Spalte für die Join-Bedingung angegeben werden. Auch hier müssen die Spalten in beiden Tabellen den gleichen Namen und Datentyp besitzen. SQL> SELECT ename, deptno, dname 2 FROM emp INNER JOIN dept USING(deptno) 3 WHERE job = ’SALESMAN’; ENAME DEPTNO DNAME ---------- --------- -------------ALLEN 30 SALES WARD 30 SALES MARTIN 30 SALES TURNER 30 SALES Join mit ON-Klausel Join Prädikate können auch mit ON definiert werden. Dies ist z.B. dann erforderlich, wenn die Spalten für die Join-Bedingung in den beiden Tabellen nicht den selben Namen haben. SQL> SELECT k.marke, k.typ, d.baujahr, d.km_stand 2 FROM kfz k INNER JOIN kfz_detail d 3 ON (k.id = d.kfz_id); MARKE ---------VW AUDI TYP ---------GOLF A4 BAUJAHR KM-STAND -------- ---------19.03.86 289000 17.07.01 16500 Es könnten auch alle anderen Bedingungen in der ON-Klausel definiert werden: SQL> SELECT marke, typ, baujahr, km_stand 2 FROM kfz k INNER JOIN kfz_detail d 3 ON (k.id = d.kfz_id 4 AND marke = ’JAGUAR’); Zu empfehlen ist diese Variante aber nicht. Es ist sinnvoller die Join-Bedingung von den einschränkenden Bedingungen (WHERE) zu trennen. Besser wäre also folgendes Statement: SQL> SELECT marke, 2 FROM kfz k 3 ON (k.id = 4 WHERE marke = typ, baujahr, km_stand INNER JOIN kfz_detail d d.kfz_id) ’JAGUAR’; Outer-Join (Left, Right und Full) Neben dem Left- und Right-Outer-Join ist mit Version 9i nun auch der Full-Outer-Join möglich. Der (+) Operator kann hier nicht mehr verwendet werden, wenn die ANSI-JoinSyntax angewendet wird. Left-Outer-Join: SQL> SELECT d.deptno, sum(nvl(e.sal,0)) sum_sal 2 FROM dept d LEFT OUTER JOIN emp e 3 ON d.deptno = e.deptno 4 GROUP BY d.deptno; DEPTNO SUM_SAL --------- --------10 8750 20 10875 30 9400 40 0 Natürlich sind sämtliche Kombinationen von Joins möglich: SQL> SELECT a.ename, a.mgr, b.ename manager, d.dname 2 FROM 3 emp a LEFT OUTER JOIN emp b 4 ON (a.mgr=b.empno) 5 INNER JOIN dept d 6 ON (a.deptno=d.deptno); ENAME MGR MANAGER ---------- ---------- ---------FORD 7566 JONES SCOTT 7566 JONES JAMES 7698 BLAKE TURNER 7698 BLAKE ... JONES 7839 KING SMITH 7902 FORD KING DNAME -------------RESEARCH RESEARCH SALES SALES RESEARCH RESEARCH ACCOUNTING 14 rows selected. Full-Outer Join: Um dieses Beispiel anschaulich darstellen zu können, wurde der Tabelle emp ein Angestellter mit empno 8000 und job ‘Controler’ aber ohne Eintrag in department hinzugefügt. Das Ergebnis eines Full-Outer Join von dept und emp sieht dann wie folgt aus: SQL> SELECT d.deptno, d.dname, e.empno, e.job 2 FROM dept d FULL OUTER JOIN emp e 3 ON (d.deptno = e.deptno); DEPTNO ---------20 30 30 20 ... 20 10 40 DNAME EMPNO JOB -------------- ---------- --------RESEARCH 7369 CLERK SALES 7499 SALESMAN SALES 7521 SALESMAN RESEARCH 7566 MANAGER RESEARCH ACCOUNTING OPERATIONS 7902 ANALYST 7934 CLERK 8000 CONTROLER 16 rows selected. Der Full-Outer-Join wird als Union-Statement optimiert: Execution Plan ---------------------------------------------------------SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=42 Bytes=1722) 0 VIEW (Cost=4 Card=42 Bytes=1722) 1 UNION-ALL 2 HASH JOIN (OUTER) (Cost=3 Card=41 Bytes=2214) 3 TABLE ACCESS (FULL) OF 'DEPT' (Cost=1 Card=41 Bytes=902) 3 TABLE ACCESS (FULL) OF 'EMP' (Cost=1 Card=41 Bytes=1312) 2 NESTED LOOPS (ANTI) (Cost=1 Card=1 Bytes=45) 6 TABLE ACCESS (FULL) OF 'EMP' (Cost=1 Card=41 Bytes=1312) 6 INDEX (UNIQUE SCAN) OF 'PK_DEPT' (UNIQUE) Sub-Query Factoring Sub-Queries bieten eine weitere Möglichkeit Daten aus mehreren Tabellen miteinander zu verknüpfen. Ein neues Feature in Oracle 9i ist hier die WITH-Klausel. Sie erlaubt einen bestimmten Teil einer Sub-Query, welcher mehrfach vorkommt, einmalig zu definieren und dann mehrfach zu verwenden. Der Optimizer entscheidet dabei, ob die benannte SubQuery als Inline View oder als Temporary Table behandelt werden soll. Das Sub- Query Factoring gehört zum SQL-99 Standard. WITH query_name AS (subquery) [, query_name AS (subquery) ]... Dazu ein Beispiel das die Mitarbeiter anzeigt, deren Gehalt über dem Durchschnittsgehalt liegt: SQL> WITH 2 emp_sal AS ( 3 SELECT deptno, ename, dname, SUM(sal) sal 4 FROM emp INNER JOIN dept USING(deptno) 5 GROUP BY ename, deptno, dname) 6 SELECT * FROM emp_sal 7 WHERE sal > 8 (SELECT avg(sal) FROM emp_sal) 9 ORDER BY deptno, ename; DEPTNO ENAME DNAME SAL ---------- ---------- -------------- ---------- 10 10 20 20 20 30 CLARK KING FORD JONES SCOTT BLAKE ACCOUNTING ACCOUNTING RESEARCH RESEARCH RESEARCH SALES 2450 5500 3000 2975 3000 2850 Execution Plan: Execution Plan ---------------------------------------------------SELECT STATEMENT Optimizer=CHOOSE 2 RECURSIVE EXECUTION OF 'SYS_LE_2_0' 0 TEMP TABLE TRANSFORMATION 2 SORT (ORDER BY) 3 FILTER 4 VIEW 5 TABLE ACCESS (FULL) OF 'SYS_TEMP_1_0_FD9D6615' 4 SORT (AGGREGATE) 7 VIEW 8 TABLE ACCESS (FULL) OF 'SYS_TEMP_1_0_FD9D6615'' Durch die WITH Klausel steigert sich nicht nur die Performance des SQL-Statements, auch dessen Übersichtlichkeit wird dadurch verbessert. Restriktionen: Der Queryname ist sichtbar für alle Sub-Queries und die Main-Query Diese Klausel kann nicht verschachtelt werden. Dies bedeutet, dass es nicht möglich ist die Sub-Query Factoring Clause als eine Sub-Query innerhalb einer anderen SubQuery Factoring Clause zu spezifizieren. In einer Query mit gesetzten Operatoren kann der Operator nicht die Sub-Query Factoring Clause beinhalten. Nur die FROM Subquery kann die Sub-Query Factoring Clause enthalten. Fazit Oracle hat mit der Version 9i im Bereich Sub-Query Factoring einige interessante Neuerungen, die die Performance von Statements betreffen, gebracht. Außerdem hat man sich jetzt auch im Bereich der Joins dem ANSI 99 Standard angepasst, was eine Erleichterung für alle Umsteiger bedeutet. Falls Sie noch mehr über die New Features von 9i erfahren wollen, dann lesen Sie weiter in Teil 3 in dem es um hierarchische Abfragen und CURSOR Expressions gehen wird. Darüber hinaus würde es uns freuen, Sie in einem unserer 9i-Kurse (NF9i, AI9-A, AI9-B) begrüßen zu dürfen. Trivadis GmbH Cityforum im Eichsfeld Ferdinand-Stuttmann-Str. 13 D-65428 Rüsselsheim Mail: Tel: Fax: Internet: [email protected] +49 6142 210 18 0 +49 6142 210 18 29 www.trivadis.com