Oracle: Table
Tabellendefinition
[Bearbeiten]Es gibt drei Arten von Tabellen:
- Relationale Tabellen
- Objekttabellen
- XML Tabellen
Die relationale Tabelle ist die Grundstruktur, um Daten zu halten. Sie ist in der Form von Spalten (Columns) und Zeilen (Rows) aufgebaut.
- Syntax
CREATE TABLE <schema.table>(
<relational properties>
);
- Beispielscript
CREATE TABLE reltable(
id NUMBER,
username VARCHAR2(50),
email VARCHAR2(50),
job VARCHAR2(50)
);
RELTABLE
ID | USERNAME | JOB | |
---|---|---|---|
1 | BBLOCKSBERG | bb@besen.hex | Hexe |
2 | BBLÜMCHEN | bb@z.oo | Dickhäuter |
Objekttabellen erweitern relationale Tabellen um die Möglichkeit der Nutzung von Objekttypen. Mindestens eine Spalte der Tabelle beinhaltet die Definition eines Objekttyps.
OBJTABLE
ID | USERINFO |
---|---|
1 | (Objectdata: BBLOCKSBERG bb@besen.hex Hexe) |
2 | (Objectdata: BBLÜMCHEN bb@z.oo Dickhäuter) |
OBJTYPE
USERNAME | JOB |
---|
. . .
Check-Constraints
[Bearbeiten]Bereits bei der Definition einer Tabelle, kann man festlegen, welche Werte oder Wertebereiche für einen Spaltenwert erlaubt oder verboten sind. Dadurch wird die Integrität der Datenbank erhöht, da nur Werte in die Datenbank eingepflegt werden können, die diesen Regeln entsprechen. Beispiel:
CREATE TABLE TEST (
T1 VARCHAR(10) NOT NULL,
T2 NUMBER(2) DEFAULT 10,
T3 NUMBER(3,2) CHECK T3 >=5
) TABLESPACE T;
NOT NULL | Bestimmt, dass der Spalte im Datensatz ein Wert zugeordnet werden muss. |
DEFAULT | Setzt einen Vorgabewert. |
CHECK | Ist eine Boolesche Regel, die wahr sein muss, damit der Datensatz akzeptiert wird. |
Primärschlüssel
[Bearbeiten]ALTER TABLE reltable ADD CONSTRAINT reltable_pk PRIMARY KEY (id);
ALTER TABLE reltable ADD PRIMARY KEY (id) DISABLE;
Fremdschlüssel
[Bearbeiten]ALTER TABLE reltable
ADD CONSTRAINT fk_reltable2
FOREIGN KEY (reltable2_id)
REFERENCES reltable2(id);
Einfügereihenfolge ermitteln
[Bearbeiten]Wenn viele Tabellen existieren, die mit Fremdschlüsseln miteinander verknüpft sind, dann kann man sich die Einfüge-Reihenfolge der Tabellen aus den Informationen im Datenbank-Distionary generieren lassen.
Beispiel für Oracle:
WITH rel AS
(
-- rel start
SELECT
child_c.table_name child
, parent_c.table_name parent
FROM user_constraints child_c, user_constraints parent_c
WHERE child_c.constraint_type = 'R'
AND child_c.r_constraint_name = parent_c.constraint_name
-- rel ende
)
, ebenen AS
(
-- ebenen start
SELECT level+1 ebene, child tabelle
FROM rel
CONNECT BY PRIOR child = parent
START WITH parent IN
(
SELECT parent
FROM rel
WHERE parent NOT IN (SELECT child FROM rel)
)
-- Ebene 1 hinzufügen
UNION
SELECT 1, parent
FROM rel
WHERE parent NOT IN (SELECT child FROM rel)
-- ebenen ende
)
-- Ermitteln und ausgeben der einzelnen Ebenen
SELECT MAX(ebene) ebene, tabelle
FROM ebenen
GROUP BY tabelle
Diese Query verwendet Informationen aus der Dictionary-View USER_CONSTRAINTS. Durch mehrere inline-Views und einem rekursivem SQL-Statement werden die gesuchten Informationen ermittelt. Die Formulierung 'CONNECT BY PRIOR' ist in Oracle eine Möglichkeit, rekursiv vorzugehen. Es werden durch 'START WITH parent IN' zuerst alle Tabellen gesucht, die keine eigenen Fremdschlüssel haben, die aber Detail-Tabellen haben (das ist die Ebene 1). Dann werden alle Tabellen gesucht, die Fremdschlüssel zu den bereits gefundenen Tabellen haben (das ist die Ebene 2). Dann werden alle neu gefundenen Tabellen untersucht, ob sie wiederum Detail-Tabellen haben. Genau das ist die Rekursion. Sie wird so lange weiter fortgesetzt, bis alle Detail-Tabellen gefunden wurden. (Ebenen 3, 4, 5, u.s.w) Die Pseudo-Spalte LEVEL gibt in Oracle bei rekursiven SQL-Statements an, wie viele Rekursions-Schritte bereits ausgeführt wurden.
Bei der oben beschriebenen Query werden Tabellen ohne Fremdschlüssel nicht ausgegeben. Falls es Ring-Verkettungen gibt, dann werden die daran beteiligten Tabellen auch nicht ausgegeben, da sie bei der 'START WITH' Klausel nicht gefunden werden. Wenn Ring-Verkettungen vorhanden sind, dann kann man diese mit der folgenden Query ausgeben. Sie verwendet auch wieder die Inline-Views REL und EBENEN und sucht schließlich nach Tabellen in USER_TABLES, die zwar in REL enthalten sind (die also Fremdschlüssel haben), die aber nicht in der View EBENEN enthalten sind. Falls eine Ring-Verkettung nur eine einzige Tabelle betrifft, also die Tabelle einen Fremdschlüssel hat, der auf die eigene Tabelle verweist, dann ist dafür noch ein weiterer Schritt erforderlich. Solche Tabellen werden gefunden mit dem Zugriff auf REL mit der Bedingung 'WHERE parent = child'.
WITH rel AS
(
-- rel start
SELECT
child_c.table_name child
, parent_c.table_name parent
FROM user_constraints child_c, user_constraints parent_c
WHERE child_c.constraint_type = 'R'
AND child_c.r_constraint_name = parent_c.constraint_name
-- rel ende
)
, ebenen AS
(
-- ebenen start
SELECT level+1 ebene, child tabelle
FROM rel
CONNECT BY PRIOR child = parent
START WITH parent IN
(
SELECT parent
FROM rel
WHERE parent NOT IN (SELECT child FROM rel)
)
-- Ebene 1 hinzufügen
UNION
SELECT 1, parent
FROM rel
WHERE parent NOT IN (SELECT child FROM rel)
-- ebenen ende
)
SELECT table_name tabelle
FROM user_tables
WHERE table_name NOT IN (SELECT tabelle FROM ebenen)
AND table_name IN (SELECT parent FROM rel)
-- Und noch alle Cycle mit nur einem Element hinzufügen
UNION
SELECT parent tabelle
FROM rel
WHERE parent = child
Die REL-View kann man auch dazu verwenden, um die dritte Gruppe von Tabellen zu finden, nämlich diejenigen, die mit Fremdschlüsseln nichts zu tun haben. Diese Tabellen haben keine eigenen Fremdschlüssel und werden auch von keiner anderen Tabelle als als Master-Tabelle referenziert. Dafür sucht man nach allen Tabellen in USER_TABLES, die weder als Parent, noch als Child in der REL-View vorkommen.
WITH rel AS
(
-- rel start
SELECT
child_c.table_name child
, parent_c.table_name parent
FROM user_constraints child_c, user_constraints parent_c
WHERE child_c.constraint_type = 'R'
AND child_c.r_constraint_name = parent_c.constraint_name
-- rel ende
)
SELECT table_name tabelle
FROM user_tables
WHERE table_name NOT IN (SELECT parent FROM rel
UNION SELECT child FROM rel)
Partitionierung
[Bearbeiten]Partitionierung nennt man den Vorgang, eine große Tabelle zwecks Performanzoptimierung in kleinere Teiltabellen zu zerlegen.
Es gibt verschiedene Arten der Partitionierung:
- Range-Partitionierung
- Hash-Partitionierung
- List-Partitionierung
- Interval-Partitionierung
Ferner kann man Partitionen noch weiter in Sub-Partitionen unterteilen.
Range-Partitionierung
[Bearbeiten]Beispiel
CREATE TABLE t_range
( t1 VARCHAR2(10) NOT NULL,
t2 NUMBER NOT NULL,
t3 NUMBER
)
PARTITION BY RANGE (t2)
( PARTITION part1 VALUES LESS THAN (1),
PARTITION part2 VALUES LESS THAN (11),
PARTITION part3 VALUES LESS THAN (MAXVALUE)
);
Eine Partition mit MAXVALUE muss nicht angegeben werden. Dann allerdings können keine Werte größer oder gleich 11 für die Spalte t2 eingefügt werden.
Die Partitionierung kann auch von mehreren Spalten abhängig gemacht werden:
CREATE TABLE t_range2
( jahr NUMBER NOT NULL,
monat NUMBER NOT NULL,
tag NUMBER NOT NULL,
zeitpunkt DATE NOT NULL,
umsatz NUMBER(14,2)
)
PARTITION BY RANGE (jahr, monat, tag)
( PARTITION p_2013 VALUES LESS THAN (2013, MAXVALUE, MAXVALUE),
PARTITION p_2014_01 VALUES LESS THAN (2014, 1, MAXVALUE),
PARTITION p_2014_02 VALUES LESS THAN (2014, 2, MAXVALUE),
PARTITION p_2014_03 VALUES LESS THAN (2014, 3, MAXVALUE),
PARTITION p_2014_04_01 VALUES LESS THAN (2014, 4, 2),
PARTITION p_2014_04_02 VALUES LESS THAN (2014, 4, 3),
PARTITION p_2014_04_03 VALUES LESS THAN (2014, 4, 4),
PARTITION p_2014_04_04 VALUES LESS THAN (2014, 4, 5),
PARTITION p_max VALUES LESS THAN (MAXVALUE, MAXVALUE, MAXVALUE)
);
In einer Query kann man sich auf die einzelnen Partitionen beziehen, indem man entweder den Namen der Partition angibt, oder die Werte, die die Partitionierung beeinflussen. Beispiel:
select * from t_range2 partition( p_2013 );
select * from t_range2 partition for ( 2013, 12, 1 );
Hash-Partitionierung
[Bearbeiten]Beispiel
CREATE TABLE t_hash
( t1 VARCHAR2(10) NOT NULL,
t2 NUMBER NOT NULL,
t3 NUMBER
PARTITION BY HASH (t2)
PARTITIONS 4
;
List-Partitionierung
[Bearbeiten]Beispiel
CREATE TABLE t_list
( ort VARCHAR2(30) NOT NULL,
t2 NUMBER,
t3 NUMBER
)
PARTITION BY LIST(ort)
( PARTITION part_nord VALUES IN ('Hamburg','Berlin'),
PARTITION part_sued VALUES IN ('Muenchen', 'Nuernberg'),
PARTITION part_west VALUES IN ('Koeln','Duesseldorf'),
PARTITION part_ost VALUES IN ('Halle'),
PARTITION part_def VALUES (DEFAULT)
);
Wenn keine Default-Partition angelegt wird, dann können für die Spalte ort nur die angegebenen Werte eingetragen werden.
Interval-Partitionierung
[Bearbeiten]Intervall-Partitionierung ist eine besondere Form der Range-Partitionierung, wobei die Spalte, von der die Partitionierung abhängt, den Datentyp DATE haben muss.
Beispiel
CREATE TABLE t_interval
( buchungs_datum DATE NOT NULL,
buchungs_text VARCHAR2(100),
betrag NUMBER(10,2)
)
PARTITION BY RANGE (buchungs_datum)
INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
( PARTITION p_historie VALUES LESS THAN (TO_DATE('2014.01.01', 'YYYY.MM.DD')),
PARTITION p_2014_01 VALUES LESS THAN (TO_DATE('2014.02.01', 'YYYY.MM.DD')),
PARTITION p_2014_02 VALUES LESS THAN (TO_DATE('2014.03.01', 'YYYY.MM.DD'))
);
Bei dieser Tabelle werden initial die drei angegebenen Partitionen angelegt. Sobald in die Tabelle Sätze eingefügt werden, bei denen der Wert für buchungs_datum nicht in die bestehenden Partitionen passt, werden automatisch weitere Partitionen erzeugt. Dabei wird pro Monat eine neue Partition erzeugt.
Man kann die Bildung neuer Intervalle jederzeit ändern. Die Änderung beeinflusst nicht die bereits existierenden Partitionen. Nur wenn neue Partitionen nach der letzten existierenden Partition gebraucht werden, kommt die Intervall-Angabe zur Anwendung.
Beispiel zur Definition, dass neue Partitionen nur im Rhythmus von jeweils 2 Jahren angelegt werden sollen:
ALTER TABLE t_interval
SET INTERVAL (NUMTOYMINTERVAL(2,'YEAR'))
;
Beispiel zur Definition, dass neue Partitionen nur im Rhythmus von jeweils 5 Tagen angelegt werden sollen:
ALTER TABLE t_interval
SET INTERVAL (NUMTODSINTERVAL(5,'DAY'))
;
temporäre Tabellen
[Bearbeiten]...
externe Tabellen
[Bearbeiten]...
LOBs
[Bearbeiten]...
Datadictionary-Views für Tabellen
[Bearbeiten]In Oracle gibt es fast alle Dictionary-Views in dreifacher Ausführung:
- Views mit dem Präfix USER_ zeigen die eigenen Objekte an, also die Objekte, die im eigenen Schema erstellt sind.
- Views mit dem Präfix ALL_ zeigen alle Objekte an, für die man eine Zugriffsberechtigung hat. Das sind die Objekte im eigenen Schema und auch Objekte in anderen Schemata, für die man durch den GRANT-Befehl eine Zugriffsberechtigung erhalten hat.
- Auf Views mit dem Präfix DBA_ kann man nur zugreifen, wenn man das Administrations-Recht hat. In dieser View werden alle Objekte der gesamten Datenbank angezeigt, also auch die, auf die man keine Zugriffsrechte besitzt.
Alle Oracle Dictionary-Views sind in dem Manual Reference (nicht: SQL-Reference) beschrieben.
Einige Beispiele
Alle eigenen Tabellen einer Datenbank anzeigen:
SELECT TABLE_NAME FROM USER_TABLES
Alle Tabellen anzeigen, auf die man zugriffsberechtigt ist:
SELECT TABLE_NAME FROM ALL_TABLES
Alle Tabellen, die es in der gesamten Datenbank gibt, anzeigen:
SELECT TABLE_NAME FROM DBA_TABLES
Alle Spaltennamen anzeigen mit den dazugehörigen Datentypen einer Tabelle:
SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, DATA_LENGTH,
DATA_PRECISION, DATA_SCALE, NULLABLE, COLUMN_ID
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = 'Tabellenname'
ORDER BY COLUMN_ID
Seit der Version 11 gibt es zusätzlich die View ALL_TAB_COLS. Der Unterschied zu ALL_TAB_COLUMNS besteht darin, dass versteckte Spalten in dieser View nicht ausgefiltert werden:
SELECT * FROM ALL_TAB_COLS
Alle Fremdschlüssel-Beziehungen und anderen Constraints anzeigen. Fremdschlüssel-Beziehungen haben den Typ 'R'. Bei DELETE_RULE = 'CASCADE' handelt es sich um eine Beziehung mit Löschweitergabe und bei 'NO ACTION' um eine Beziehung mit Lösch-Restriktion.
SELECT CONSTRAINT_NAME, TABLE_NAME, R_CONSTRAINT_NAME REFERENCED_TABLE, DELETE_RULE
FROM USER_CONSTRAINTS
WHERE CONSTRAINT_TYPE = 'R'
Tabellen-Kommentare werden in einer eigenen View bereitgestellt:
SELECT TABLE_NAME, TABLE_TYPE, COMMENT
FROM ALL_TAB_COMMENTS
Ab der Version 11g gibt es eine eigene View zur Ausgabe von Statistik-Daten:
SELECT * FROM ALL_TAB_STATISTICS
Zusätzliche Informationen über partitionierte Tabellen. Jede partitionierte Tabelle hat hier einen Eintrag:
SELECT * FROM ALL_PART_TABLES
Informationen über Partitionen und Sub-Partitionen. Jede Partition bzw. Sub-Partition hat hier eine eigene Zeile:
SELECT * FROM ALL_TAB_PARTITIONS
SELECT * FROM ALL_TAB_SUBPARTITIONS
Tabellen verkleinern
[Bearbeiten]Wenn man Sätze aus einer Tabelle löscht, dann wird der Speicherplatz im Tablespace trotzdem nicht freigegeben. Alle Datenblöcke, die einmal für die Speicherung von Daten für eine bestimmte Tabelle verwendet wurden, bleiben dieser Tabelle zugeordnet und können nicht zur Speicherung von Daten in anderen Tabellen benutzt werden. Wenn man eine Tabelle nur vorübergehend mit einem großen Datenvolumen gefüllt wurde und der Speicherplatz danach für andere Tabellen zur Verfügung gestellt werden soll, dann gibt es verschiedene Möglichkeiten:
- ALTER TABLE MOVE TABLESPACE
- EXPORT / drop Table / create Table / IMPORT
- ALTER TABLE SHRINK SPACE
Die Varianten 1 und 2 haben den Nachteil, dass es eine Ausfallzeit gibt, in der andere Programme, die auf diese Tabelle zugreifen wollen, eine Fehlermeldung bekommen.
Die Variante 3 gibt es seit der Version 10g. Sie hat den Vorteil, dass die Tabelle nur durch einen Lock gesperrt wird. Andere Programme müssen so lange warten, bis die Verkleinerung fertig ist, sie bekommen aber keine Fehlermeldung.
Der Befehl ALTER TABLE SHRINK SPACE ist an bestimmte Bedingungen geknüpft:
Verkleinern kann man damit
- Tabellen
- Indizes
- indexorganisierte Tabellen
- Partitionen
- Subpartitionen
- LOB Segmente (ab Version 10.2)
- Materialized Views
Voraussetzungen
- Oracle RDBMS ab Version 10g.
- Der Tablespace muss mit der Option SEGMENT MANAGEMENT AUTO angelegt sein.
- Bei der Tabelle, die verkleinert werden soll, muss ROW MOVEMENT aktiviert sein.
Einschränkungen
- Die Tabelle darf nicht komprimiert sein.
- Die Tabelle darf keine FUNCTION BASED Indizes besitzen.
- Die Mastertabelle einer ON COMMIT MATERIALIZED VIEW kann nicht verkleinert werden.
- ROWID MATERIALIZED VIEWS müssen nach dem Verkleinern neu aufgebaut werden.
- Tabelle darf keine LOB oder LONG Spalten besitzen (nur in Version 10.1).
- Der Befehl SHRINK SPACE ist eine Art der Reorganisation. Dadurch ändern sich die ROWIDs.
alter table test ENABLE ROW MOVEMENT;
alter table test SHRINK SPACE;