Хотя для студентов и сотрудников есть только несколько отдельных столбцов, я бы сказал, что все просто:
CREATE TABLE person (
person_id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY
, name text
, birthday date -- never age! bitrots in no time
, student_number int
, staff_number int
, salary numeric
, hired_at date
, staff_type text
, CONSTRAINT one_role_max CHECK (student_number IS NULL
OR (staff_number, salary, hired_at, staff_type) IS NULL)
, CONSTRAINT one_role_min CHECK (student_number IS NOT NULL
OR (staff_number, salary, hired_at, staff_type) IS NOT NULL)
);
CREATE TABLE users (
user_number int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
, person_id int NOT NULL REFERENCES person
, password text -- encrypted !
);
Таким образом, один человек может иметь 0-n учетных записей пользователей - это типичная реальность. Вы можете ограничиться одной учетной записью на человека, добавив UNIQUE (person_id)
к таблице users
.
Ограничение CHECK
one_role_max
требует, чтобы столбцы учеников или столбцы сотрудников оставались пустыми.
CHECK
ограничение one_role_min
обеспечивает, что хотя бы один из них должен иметь какие-либо значения.
Адаптировать то, что должно / может быть заполнено, к вашим потребностям. Выражения работают отлично для текущего дизайна. См .:
Хотя это строго «или / или», и единственный столбец студента - student_number
, этот запрос отвечает на ваш вопрос:
SELECT CASE WHEN student_number IS NULL THEN 'staff' ELSE 'student' END AS user_role
FROM person
WHERE person_id = (SELECT person_id FROM users WHERE user_number = 98242);
Или удалите одно или оба ограничения CHECK
, чтобы разрешить одному и тому же человеку учиться и персоналу, или ни одному. Адаптируйте вышеуказанный запрос соответствующим образом.
Вы могли бы использовать наследование для этого (как демонстрирует Абелисто), но я бы предпочел держаться от него подальше. Когда-то была идея объектно-реляционной СУБД. Но сообщество в значительной степени продвинулось. Это работает, но с предостережениями . Разделение раньше было основным вариантом использования. Но декларативное разбиение в Postgres 10 в основном заменило реализацию на основе наследования. Интерес к нему уже не слишком велик.
А как насчет всех этих пустых столбцов? Я трачу там много места? Противоположный случай. Объем диска не станет намного меньше, чем этот. НУЛЕВОЕ хранилище очень дешево. См .: