PD>Вот только с UNION вопрос. Таблицы-то сильно разные. В них вообще может не быть одинаковых по смыслу полей, кроме ID, и то, если он в них есть(они могли бы использовать ID базовой как свой PK). Что брать-то ? И как потом определить, откуда взяли ?
Сорри, если не к месту вмешиваюсь и вообще уже поздно, но здесь я не понял — причём тут UNION, когда нужны просто два LEFT JOIN (или три для добавления в выборку данных по факультету в случае, когда студент в группе):
select * from students s --вместо звездочки - нужные поля, естественно, разные из groups и faculties.
inner join facs_groups fg on s.fac_group_id=fg.id --джойн с базовой таблицей групп/факультетов
left join faculties f on f.id=fg.id --факультет; выбираемые поля f.* будут NULL, если студент в группе
left join groups g on g.id=fg.id --группа; выбираемые поля g.* будут NULL, если студент НЕ в группе
left join faculties ff on g.fac_id=ff.id --факультет по группе; выбираемые поля ff.* будут NULL, если студент НЕ в группе
поля по факультету, чтобы не дублировать в выборке f.* и ff.*, логично выбирать через COALESCE(f.поле, ff.поле) AS поле
BTW, оставаясь в рамках ООП-идеологии, для исключения "лишней по Оккаму" базовой таблицы можно
посчитать группу базовым классом, а факультет — его наследником, и в результате получится точно такая же структура данных, что и в решении с "псевдогруппами для студентов без группы" — т.е. "псевдогруппа" и "факультет как его предок, т.е. группа" — это по сути одна и та же сущность.
(И тогда вышеприведенный запрос упрощается с четырех JOIN до всего двух, а это явный выигрыш!)