Verwenden einer Referenz VOR Definition der referenzierten Tabelle

Hallo,

eine kleine Frage:

gibt es eigentlich eine Möglichkeit, in der Definition einer Tabelle mit CREATE TABLE eine Referenz auf eine andere Tabelle zu definieren, die erst später definiert wird?
Konkreter Hintergrund: ich habe ein ziemlich langes Skript mit den Tabellendefinitionen (zur Zeit ausgedruckt etwa 120 Seiten) das mir die Datenbank erstellt, wenn ich es in pgsql “hineinstecke”. Bei der Erweiterung einer Tabelle kommt es nun vor, das ich nachträglich in einer Tabelle einen Fremdschlüssel auf eine Tabelle anlege, die erst weiter unten im Skript definiert wird. Dann ist fröhliches umsortieren angesagt, was beliebig komplex werden kann.
Gibt es vielleicht eine Möglichkeit, eine Art Tabellen-Prototyp zu definieren und die konkrete Definition dann später vorzunehmen?
Ich denke da an TurboPascal: dort war es so, dass eine Funktion erst aufgerufen werden durfte, NACHDEM sie definiert wurde. Wenn sich zwei Funktionen jedoch wechselseitig aufrufen sollten, so konnte eine Funktion erst als Prototyp - d.h. nur der Funktionskopf mit Parameterliste - und später erst der eigentliche Funktionskörper definiert werden.
Ich habe mal irgendwann etwas ähnliches zu PostgreSQL gelesen, finde die Seite aber nicht wieder :frowning:

Kann mir jemand etwas dazu sagen? Danke

Meines Wissens nach ist dies nicht möglich. Eine Referenz muss existieren, sobald sie beim Erstellen einer Tabelle genutzt werden möchte.

IMHO nein, aber Du könntest mit ALTER TABLE Deinen Foreign Key später setzen, wenn die andere Tabelle existiert.

Andreas

Mit dem ALTER TABLE habe ich es auch bisher realisiert. Ist eigentlich schade, dass es keine andere Moeglichkeit gibt, da so die Definition der Tabelle “auseinandergerissen” wird.

Vielleicht wäre so ein “Tabellen-Prototyp” eine Anregung für eine spätere Version von PostgreSQL?

Trotzdem vielen Dank für die Antworten.

Ich schätze, die vorgreifende Frage ist: wie häufig braucht man so etwas?
In der Regel schreibt man seine Tabellen so, das diese aufeinander aufbauen. Das trifft nun in deinem Fall gerade mal nicht zu.

Aber um deine Idee nicht ganz zu verwerfen, unterbreite doch den Vorschlag mal auf einer der Entwicklermailinglisten.

Sehr häufig kommt es wahrscheinlich nicht vor - das ist richtig. Spontan fallen mir zwei Szenarien ein:

  1. Kreuzweises referenzieren von Tabellen
  2. Lästiges umsortieren in der Entwicklungsphase fällt weg

Gerade Punkt 2 hängt natürlich sehr davon ab, wie man entwickelt.
Bei mir läuft das so, dass ich ein großes Skript habe, in dem die Tabellen, Funktionen, Views usw. definiert werden. Dieses Skript kann ich dann bequem in ein System zur Versionskontrolle einchecken. Um Änderungen in die (Test-)Datenbank einzuspielen, habe ich mir ein Makefile gebastelt, das die Daten aus der Datenbank in ein Dump spielt, die Datenbank löscht, das Skript zum Erstellen der Datenbank durchlaufen lässt und dann den Dump wieder zurückspielt.
Wenn ich dann eine Version der Datenbank freigebe und auf den Produktivserver einspiele, muss ich dort nur die aktuelle Version der DB-Definition auschecken und das Makefile anwerfen - der Rest läuft automatisch.
In dem Skript mit den Tabellendefinitionen muss ich dann eben recht häufig mal Tabellen umsortieren, damit die Erzeugung sauber durchläuft. Da ich thematisch zusammengehörende Tabellen aber gerne auch räumlich dicht zusammenstehen habe, mag ich ein solches umsortieren natürlich nicht so gerne (vom Zeitaufwand mal abgesehen)

Da kann Dir geholfen werden:

test=> create table t1 (id int primary key, name_t1 text);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index “t1_pkey” for table “t1”
CREATE TABLE
test=> create table t2 (id int primary key, fk int references t1 deferrable, name_t2 text);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index “t2_pkey” for table “t2”
CREATE TABLE
test=
> alter table t1 add constraint c1 foreign key (id) references t2 deferrable;
ALTER TABLE
test=> SET CONSTRAINTS ALL DEFERRED;
SET CONSTRAINTS
test=
> insert into t1 values (1,‘name1’);
INSERT 0 1


Ohne das SET CON… gäbe es beim Insert einen Fehler. Wenn ich nun vergesse, in der anderen Table das noch einzutragen, bekomme ich meinen Error halt erst beim COMMIT:

test=*> commit;
ERROR: insert or update on table “t1” violates foreign key constraint “c1”
DETAIL: Key (id)=(1) is not present in table “t2”.


Du suchst also quasi ein DEFERRED für DDL, und das kannst Du ja auch gern mal Tom oder so vorschlagen.

Andreas