Sample Header Ad - 728x90

Referencial integrity for hierarchical tables

2 votes
1 answer
72 views
Let's say I have the following tables describing some vehicles
CREATE TABLE class (
  id INT GENERATED ALWAYS AS IDENTITY,
  label TEXT NOT NULL,

  PRIMARY KEY (id, label),
  UNIQUE (id)
);

CREATE TABLE maintenance_frequency (
  id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  class_id INT REFERENCES class (id),
  freq FLOAT NOT NULL
);

CREATE TABLE function (
  id INT GENERATED ALWAYS AS IDENTITY,
  class_id INT REFERENCES class (id),
  label TEXT NOT NULL,

  PRIMARY KEY (id, label),
  UNIQUE (id)
);

CREATE TABLE vehicle (
  id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  label TEXT  NOT NULL,
  class_id INT REFERENCES class (id),
  freq_id INT REFERENCES maintenance_frequency (id),
  fun_id INT REFERENCES function (id)
  
);
INSERT INTO class(label) VALUES
('car'),
('motorbike');


INSERT INTO function(class_id, label) VALUES
(1, 'leisure'),
(1, 'work'),
(2, 'beach trip');

INSERT INTO maintenance_frequency(class_id, freq) VALUES
(1, 0.5),
(1, 1.0),
(2, 1.5),
(2, 2.0);
SELECT * FROM class;
SELECT f.id, c.label as class, f.label as function FROM function as f 
  INNER JOIN class as c ON c.id = f.class_id;
SELECT mf.id, c.label as class, mf.freq FROM maintenance_frequency as mf 
  INNER JOIN class as c ON c.id = mf.class_id;
| id | label | |---:|:------| | 1 | car | | 2 | motorbike | | id | class | function | |---:|:------|:---------| | 1 | car | leisure | | 2 | car | work | | 3 | motorbike | beach trip | | id | class | freq | |---:|:------|:-----| | 1 | car | 0.5 | | 2 | car | 1 | | 3 | motorbike | 1.5 | | 4 | motorbike | 2 | So, a vehicle can be of class "car" or "motorbike", and based on that, can be assigned 1 maintenance frequency value in (0.5, 1.0) and can be a assigned a function in ("leisure", "work") if it's a car, while for a motorbike the frequencies are (1.5, 2.0) and just ("beach trip") for what concerns function. For simplicity, let's assume a vehicle can be assigned only one "feature" (i.e. can be related to just one row of each "feature table"). I'd like to know how to enforce the right constraints in order to ensure that:
-- This should work
INSERT INTO vehicle(label, class_id, freq_id, fun_id) VALUES
('Alice', 1, 1, 1);
--- This should not work because freq_id=3 is for motorbikes
INSERT INTO vehicle(label, class_id, freq_id, fun_id) VALUES
('Bob', 1, 3, 1)
--- This should not work because fun_id=3 is for motorbikes
INSERT INTO vehicle(label, class_id, freq_id, fun_id) VALUES
('Charlie', 1, 1, 3)
--- Third row should not be possible 
SELECT v.label, c.label as class, f.label as function, mf.freq FROM vehicle as v
INNER JOIN class as c ON c.id = v.class_id
INNER JOIN maintenance_frequency as mf ON mf.id = v.freq_id
INNER JOIN function as f ON f.id = v.fun_id;
| label | class | function | freq | |:------|:------|:---------|:-----| | Alice | car | leisure | 0.5 | | Bob | car | leisure | 1.5 | | Charlie | car | beach trip | 0.5 | [fiddle](https://dbfiddle.uk/9RUY1y5L)
Asked by rdbisme (121 rep)
Nov 14, 2022, 02:56 PM
Last activity: Nov 15, 2022, 09:41 AM