Zähler in Wohnungen und Häusern

Hey All,
ich schreibe gerade an einer kleinen Anwendung zum speichern von Zählerständen.
Zähler können sich in Wohnungen und Häusern befinden.
Nun habe ich beim Zähler zwei Spalten (building_id und flat_id) wovon lediglich eine benutzt wird.
Macht man das so oder gibt es eine bessere Lösung für so ein Problem?
Hier mein Code:
CREATE TABLE buildings(
id SERIAL UNIQUE PRIMARY KEY,
itime TIMESTAMP DEFAULT NOW(),
mtime TIMESTAMP DEFAULT NOW(),
description TEXT,
street TEXT,
zipcode TEXT,
city TEXT
);
DROP TABLE IF EXISTS flats CASCADE;
CREATE TABLE flats(
id SERIAL UNIQUE PRIMARY KEY,
itime TIMESTAMP DEFAULT NOW(),
mtime TIMESTAMP DEFAULT NOW(),
description text,
building_id int REFERENCES buildings( id )
);
DROP TABLE IF EXISTS meters CASCADE;
CREATE TABLE meters(
id SERIAL UNIQUE PRIMARY KEY,
itime TIMESTAMP DEFAULT NOW(),
mtime TIMESTAMP DEFAULT NOW(),
–unit_id int REFERENCES units( id ),
flat_id int REFERENCES flats( id ), --ist das sinnvoll??
building_id int REFERENCES buildings( id )
);

Dank und Gruß
Ronny

wenn es das Datenmodell so vorgibt, warum nicht? Du könntest noch einen CHECK-Constraint definieren, daß einer der FKs gesetzt sein muß, und auch nur einer.

Man könnte das Modell auch ein klein wenig abstrakter machen:
Ein meter gehört immer zu einem flat.
Ein flat gehört zu einem building.

Ich vermute mal, flat soll Wohnung sein, aber es gibt auch Zähler, die man nicht zu einer Wohnung zuordnen kann, weil sie z.B. den Strom im Flur oder sonst. gemeinsam genutzten Flächen erfassen, dann würde ich dazu auch ein “flat” definieren.
Man kann ja in flat eine Spalte “type” haben , dass dann ‘wohnung’, ‘flur’, garage’ oder wie auch immer, das flat genauer spezifiziert. In meters habe ich dann aber keine building_id mehr, das ist m.E. kein gutes Modell.

Ist sicherlich ein valider Ansatz, aber dann würde ich die Tabelle umbenennen, z.B.“object” oder etwas ähnlich generisches (das englische “unit” könnte man auch für “Verwaltungseinheit” verwenden, aber offensichtlich verwendest Du das schon für was Anderes). Die “type” Spalte würde ich dann hinzunehmen, wenn es wichtig zu wissen ist, ob der Zähler wirklich in einer Wohnung angebracht ist (z.B. wegen unterschiedlicher Tarife oder etwas ähnlichem)

Das macht aber nichts, weil die Zuordnung zum Gebäude immer noch eindeutig ist (via “flat” bzw. “object” - oder wie auch immer die Tabelle dann heißt)

Ja gute Idee mit dem CHECK-Constraint;
Leider gelingt es mir nicht das zu implementieren.
Ich habe es so:

DROP TABLE IF EXISTS meters CASCADE; 
CREATE TABLE meters(
    flat_id int  CHECK( flat_id > 0 AND building_id IS NULL ),
	building_id int  CHECK( building_id > 0 AND flat_id IS NULL )
	--CHECK( ( building_id = NULL AND flat_id > 0 ) OR ( flat_id = NULL AND building_id > 0 ) )
);
INSERT INTO meters ( building_id ) VALUES ( 1 );
--INSERT INTO meters ( flat_id, building_id ) VALUES ( 1, 1 );

Wie checke ich ob eine Spalte NULL ist??
Oder habe ich da einen Denkfehler??

VG Ronny

test=# create table ta (id int primary key);
CREATE TABLE
test=# create table tb (id int primary key);
CREATE TABLE
test=
# create table tab (a int references ta, b int references tb, check ((case when a is null then 1 else 0 end + case when b is null then 1 else 0 end) = 1));
CREATE TABLE

Du kannst nicht Spalte = NULL prüfen, das geht nicht.

Das kann man sehr schön via num_nonnulls testen:

CREATE TABLE meters
(
  flat_id int references flats,
  building_id int references buildings,
  constraint at_least_one_id check ( num_nonnulls(flat_id, building_id) = 1 )
)

Die Prüfung > 0 macht keinen Sinn, nur die Prüfung auf NOT NULL is sinnvoll.

num_nonnulls(flat_id, building_id) = 1 bedeutet, dass immer genau eine Spalte NULL und die andere NOT NULL sein muss

cool, kannte ich nicht …

Juju so funktionierts.