Как организовать таблицы в бд?
Есть несколько основных вариантов реализации:

1. как Вы указали: одна таблица, неиспользуемые поля делать null. Это паттерн Single Table Inheritance. Работает хорошо, если типов и дополнительных полей будет немного.

2. одна таблица для общих свойств (имя, фамилия, емаил, пароль), вторая для преподавателей, третья для администраторов. У второй и третьей необходимые им поля. Это паттерн Multiple/Class Table Inheritance. Достаточно гибкий вариант, но необходимо будет использовать join. 

Вот здесь есть несколько примеров https://romaricdrigon.github.io/2019/06/11/doctrin...
Дополню и поправлю ответ Дмитрий, с первым вариантом все понятно и так, единственное уточнение - это максимально не гибко и в реальных проектах считается плохой практикой. Если завтра в данную структуру понадобится добавлять новые сущности - вся структура идет по бороде и вы должны будете все перестраивать.

Со вторым вариантом все более-менее неплохо, единственное что не упомянуто - в базовой таблице нужно хранить еще и тип пользователя, и join при такой структуре теряет смысл, так как вам в любом случае придется выполнять 2 запроса - один чтобы авторизироваться, другой чтобы получить данные из нужной таблицы, исходя из типа пользователя, ну или заморачиваться с достаточно сложными запросами на основе ифов и тд, что становится еще хуже с добавлением дополнительных сущностей. В идеале еще должна быть справочная таблица типов пользователей, но это уже нюансы.

Ну и есть 3 вариант, который в данном КОНКРЕТНОМ случае подходит меньше, но в целом более подходит под смысл - общая таблица сущностей с базовыми параметрами + множество атрибутов для подгрупп сущностей. Называется EAV.