1 - oth-regensburg.de

Werbung
Datenbanken
8. Übung
Aufgabe: Hierarchische Beziehungen in relationalen DB
Eine hierarchische Beziehung in der Datenbank für das Personalwesen ist bspw. die Beziehung
"Vorgesetzter" zwischen Arbeitnehmern (Angestellte) in einem Unternehmen. Voraussetzung für die
Entwicklung einer hierarchischen Beziehung ist ein Feld "Vorgesetzter" in der Tabelle "Angestellte".
Die Angestellten, die "große Vorgesetzte" sind (d.h. "Vorgesetzte der Vorgesetzten") haben im Feld
"Vorgesetzter" den Eintrag "null" stehen. Die Daten zum Personalwesen erweitern sich um
Vorgesetzte folgendermaßen:
ANG_ID
NAME
GEBJAHR
ABT_ID
JOB_ID
QUALI
A16
A17
A18
A19
A20
A15
A21
Bernd
Dieter
Gustav
Karl
Kurt
Christian
Liesel
22.9.1948
12.9.49
11.5.42
2.4.1951
3.10.1941
17.11.1940
17.8.1956
OD
PA
KO
RZ
VT
LT
LT
AL
AL
AL
AL
AL
GF
SK
AL,SY
AL, IN
AL, IN
AL,PR
AL.KA
GF
SK
Ein ERM-Diagramm würde den Sachverhalt so beschreiben:
Lösungsvorschlag:
1. Erweiterung bzw. Veränderung der Tabelle Angestellte um das Feld "Vorgesetzter"
Die Tabelle Angestellte muß um die Spalte VORGESETZTER erweitert werden:
ANGESTELLTE
ANG_ID NAME
A1
Fritz
A2
Tom
A3
Werner
A4
Gerd
A5
Emil
GEBJAHR
2.1.1950
2.3.1951
23.4.1948
3.11.1950
2.3.1960
ABT_ID
OD
KO
OD
VT
PA
JOB_ID
SY
IN
PR
KA
PR
1
VORGESETZTER
A16
A18
A16
A20
A17
VORGESETZTER
A15
A15
A15
A15
A15
null
A15
Datenbanken
A6
A7
A8
A9
A10
A11
A12
A13
A14
Uwe
Eva
Rita
Ute
Willi
Erna
Anton
Josef
Maria
3.4.1952
17.11.1955
02.12.1957
08.09.1962
7.7.1956
13.10.1966
5.7.1948
2.8.1952
17.09.1964
RZ
KO
KO
OD
KO
OD
OD
KO
PA
OP
TA
TA
SY
IN
KA
SY
SY
KA
A19
A18
A18
A16
A18
A16
A16
A18
A17
Veränderung an der Tabellenstruktur sind über ALTER TABLE ... vorzunehmen:
ALTER TABLE <TABLE NAME> ADD|DROP|MODIFY (<Spalten Spezifikationen...>1);
Im vorliegenden Fall führt das zu: ALTER TABLE angestellte ADD(Vorgesetzter VARCHAR2(3));
2. Füllen der neuen Spalte mit Daten2.
Die Daten sind in die neue Spalte mit der UPDATE-Anweisung einzubringen:
UPDATE <Spalte(n)>
SET <Spalten-Name> = <Wert>
[WHERE <Bedingung>];
2. Erweiterung der Tabellen "job" bzw. Qualifikation um "leitende Positionen".
JOB
JOB_ID
KA
TA
SY
PR
OP
AL
GF
SK
TITEL
Kaufm. Angestellter
Techn. Angestellter
Systemplaner
Programmierer
Operateur
Abteilungsleiter
Geschaeftsfueher
Sekretaerin
GEHALT
3000,00 DM
3000,00 DM
6000,00 DM
5000,00 DM
3500,00 DM
7500,00 DM
9000,00 DM
2500,00 DM
QUALIFIKATION
ANG_ID
JOB_ID
A1
SY
A1
PR
A1
OP
A2
IN
A2
SY
A3
PR
A4
KA
A5
PR
A6
OP
A7
TA
A8
IN
A9
SY
A10
IN
A11
KA
A12
SY
A13
IN
A14
KA
1
2
vgl. CREATE-Befehl
vgl. ueb8.sql
2
Datenbanken
A16
A16
A17
A17
A18
A18
A19
A19
A20
A20
A15
A21
AL
SY
AL
KA
AL
IN
AL
PR
AL
KA
GF
SK
3. Auswahl der hierarchischen Beziehungen.
Sie erfolgt über
a) die Beziehung zwischen oberen und unteren Knoten in der Hierarchie.
Die hierarchische Beziehung wird durch die CONNECT BY -Klausel bestimmt. Damit wird die
Beziehung zwischen Vorgänger und Nachfolgerknoten hergestellt, die Angabe PRIOR ist ein Verweis
auf den Vorgängerknoten.
b) Die Wurzel der Hierarchie
Sie wird durch die START WITH -Klausel definiert.
select ang_id, name, vorgesetzter
from angestellte
connect by prior ang_id = vorgesetzter
start with ang_id = 'A15'
order by name;
Für Baumstrukturen ist die Einführung eines Pseudo-Felds LEVEL möglich, das die Tiefe des
jeweiligen Satzes (Hierarchiestufe) angibt. Die Wurzel des Baums hat die Tiefe 1.
select max(level) from angestellte
connect by prior ang_id = vorgesetzter;
Eine Darstellung, die die hierarchischen Beziehungen besonders gut angibt 3, erhält man mit Hilfe der
Funktion LPAD (padding from left, Auffüllen von links).
select lpad('-',(level-1)*3,'+--') || name || ' -- ' organigramm
from angestellte
connect by prior ang_id = vorgesetzter
start with name = 'Christian';
Eine Analyse vom Blatt zur Wurzel zeigt:
select level, name, ang_id, vorgesetzter
from angestellte
connect by ang_id = prior vorgesetzter
start with name = 'Gerd';
Zusaetzliche Bedingung können in der where-Klausel angegeben werden
select level, name, ang_id, vorgesetzter
from angestellte
where name != 'Bernd'
connect by prior ang_id = vorgesetzter
start with name = 'Christian';
3
vgl. ueb8.sql
3
Datenbanken
Wenn zusaetzliche Bedingungen in der connect by-Klausel eingefuegt werden, werden ganze Teile
der Hierarchie nicht dargestellt
select level, name, ang_id, vorgesetzter
from angestellte
connect by prior ang_id = vorgesetzter
and name != 'Bernd'
start with name = 'Christian';
Eine Darstellung eines Baums mit mehreren Startpunkten
select level, a1.ang_id, a1.name, a1.vorgesetzter
from angestellte a1
connect by prior a1.ang_id = a1.vorgesetzter
start with a1.ang_id in
(select a2.ang_id
from angestellte a2, job
where a2.job_id = job.job_id
and job.titel = 'Abteilungsleiter');
Die Benutzung von connect by in einer Subquery zeigt
select a1.name, abt.bezeichnung
from angestellte a1, abteilung abt
where a1.abt_id = abt.abt_id
and ang_id in
(select a2.ang_id
from angestellte a2
connect by ang_id = prior vorgesetzter
start with name = 'Gerd');
In der FROM-Klausel einer Abfrage mit CONNECT BY darf nur eine Tabelle oder ein View stehen. Es
ist somit auch nicht möglich, den CONNECT BY –Operator innerhalb eines Join zu verwenden. Auch
darf ein veränderter View wiederum nur auf eine Tabelle aufbauen. Eine Alternative für die
Kombination von Join und CONNECT BY ist jedoch vorhanden.
Gib alle Mitarbeiter auf Hierarchiestufe 3 an.
4. Hierarchische Abfragen in Oracle Version 9i
Bisher (vor Oracle Version 9i) galten folgende Einschränkungen:
- Eine Sortierung mit der ORDER BY –Klausel übersteuerte die gefunden Hierarchie
- ein Join oder eine View, die einen JOIN beinhalteten, konnte nicht verwendet werden
- eine Master-Detail –Beziehung musste demzufolge immer in der gleichen Tabelle abgelegt sein
- eine Sub-Query war nicht erlaubt
Join-Beziehung. Die Verwendung eine Join in einer CONNECT BY –Klausel ist nun problemlos
möglich
select substr(lpad('/',2*level,'-') || name,1,15) "NAME",
abt_id, bezeichnung, level
from angestellte NATURAL JOIN abteilung
start with vorgesetzter is null
connect by prior ang_id = vorgesetzter;
Erstellen einer Hilfstabelle
create table t_mgr as select ang_id, vorgesetzter from angestellte;
select * from t_mgr;
Abfrage mit zusammengesetzter Master-Detail Beziehung
4
Datenbanken
select substr(lpad ('/', 2*level,'-') || name, 1, 15) "NAME",
a.ang_id, level
from angestellte a join t_mgr m on (a.ang_id = m.ang_id)
start with m.vorgesetzter is null
connect by prior a.ang_id = m.vorgesetzter;
drop table t_mgr;
Selbst eine connect-by Klausel auf einen View, der einen join beinhaltet, kann nun verwendet werden
create view v_ang_abt
(ang_id, name, vorgesetzter, job_id, abt_id, bezeichnung)
as
select ang_id, name, vorgesetzter, job_id, abt_id, bezeichnung
from angestellte natural join abteilung;
select substr(lpad('/',2*level,'-') || name,1,15) "NAME",
titel, level
from v_ang_abt, job
where v_ang_abt.job_id = job.job_id
start with vorgesetzter is null
connect by prior ang_id = vorgesetzter;
drop view v_ang_abt;
Resultate einer hierarchischen Anwendung konnten über ORDER BY nicht sinnvoll sortiert werden, z.
B.
select substr(lpad('/',2*level,'-') || name,1,15) "NAME",
abt_id, bezeichnung, level
from angestellte NATURAL JOIN abteilung
start with vorgesetzter is null
connect by prior ang_id = vorgesetzter
order by name;
In Oracle 9i steht die ORDER SIBLINGS BY –Klausel zum Sortieren bereit. Das Schlüsselwort
SIBLINGS bewirkt, dass beim Sortiervorgang die vorhanden Hierarchie berücksichtigt wird.
select substr(lpad('/',2*level,'-') || name,1,15) "NAME",
abt_id, bezeichnung, level
from angestellte NATURAL JOIN abteilung
start with vorgesetzter is null
connect by prior ang_id = vorgesetzter
order siblings by name;
Nei ist auch die SYS_CONNECT_BY_PATH –Klausel. Sie veranschaulicht den hierarchischen Weg
zum Root-Element. Der zweite Parameter gibt das Trennzeichen zwischen den verschiedenen Stufen
an.
select substr(sys_connect_by_path(name,'/'),1,30) "name", level
from angestellte
start with vorgesetzter is null
connect by prior ang_id = vorgesetzter
order siblings by name;
Eine Sub-Query in der CONNECT BY –Klausel ist weiterhin nicht erlaubt, z.B:
select name, ang_id, vorgesetzter
from angestellte
start with vorgesetzter is null
connect by prior ang_id = (select vorgesetzter
from angestellte
5
Datenbanken
where name = 'Christian');
Neu ist nur die Möglichkeit eine Sub-Query in der FROM-Klausel anzusprechen.
select substr(lpad('/',2*level,'-') || name,1,15) "NAME",
abt.abt_id, bezeichnung, level
from angestellte ang, (select bezeichnung, abt_id from abteilung) abt
where abt.abt_id = ang.abt_id
start with vorgesetzter is null
connect by prior ang_id = vorgesetzter;
SQL-Skript 1
SQL-Skript 2
6
Herunterladen