Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Qulac, Вы писали:
PD>>>Вот только с UNION вопрос. Таблицы-то сильно разные. В них вообще может не быть одинаковых по смыслу полей, кроме ID, и то, если он в них есть(они могли бы использовать ID базовой как свой PK). Что брать-то ? И как потом определить, откуда взяли ?
Q>>В чем проблема нужный запрос написать, sql поддерживает условные операторы CASE и IIF?
PD>Да ради бога, а что брать-то и как определить, откуда взяли
PD>В таблице группы есть одно поле number int. И FK на базовую PD>В таблице факультет есть одно поле name varchar. И FK на базовую, конечно
PD>Что брать-то ?
Вот так например:
DECLARE @student_id INT = 2;
declare @faculty varchar(50);
declare @group varchar(50);
-- если у студента нету ссылки на факультет, то он зачислен в группу и все данные получаем по связи от группыif((select count(*) from students inner join students_sets on students.students_set_id=students_sets.students_set_id
inner join faculties on faculties.faculties_id=students_sets.students_set_id
where students.students_id = @student_id) = 0)
begin
set @group = (select groups.number
from students
inner join students_sets on students.students_set_id=students_sets.students_set_id
inner join groups on groups.groups_id = students_sets.students_set_id
where students.students_id=@student_id)
set @faculty = (select faculties.Name
from students inner join students_sets on students.students_id=students_sets.students_set_id
inner join groups on students.students_set_id=groups.groups_id
inner join faculties on faculties.faculties_id= groups.faculties_id
where students.students_id=@student_id)
end
else
begin
set @faculty = (select faculties.Name
from students inner join students_sets on students.students_id=students_sets.students_set_id
inner join faculties on faculties.faculties_id=students_sets.students_set_id
where students.students_id = @student_id);
end
select @faculty as 'Факультет', @group as 'группа'
Программа – это мысли спрессованные в код
Re[14]: и еще один вопрос по реляционной структуре
Здравствуйте, Qulac, Вы писали:
Q>Вот так например:
<skipped>
Ну не знаю. Может быть, это и будет работать, но нужно серьезное тестирование.
Вижу 2 таблицы : students и students_sets. Первая, полагаю, все студенты, а вторая что такое ?
И где тут базовая (в терминах предыдущих твоих постингов) таблица ? Или она и есть students_sets ?
В общем, рекомендовать это студентам я бы не стал. ИМХО слишком тяжелая артиллерия для , в общем-то, простой ситуации. В конце концов 2 FK от студента на группу и факультет хоть и не очень хорошо с точки зрения канонов, но терпимо.
Ну и концептуально мне это решение не нравится. Получается, что таблицы факультет и группа — братья и оба "потомки" от базовой. А по смыслу все же факультет : группа == parent:child. И не стоит ради того, чтобы решить локальную проблему, портить структуру .
А вот это решение вообще снимает все проблемы легко и изящно
Здравствуйте, m2user, Вы писали:
M>Виртуальная группа (одна на каждый факультет) в таблице `group` c FK на faculty. M>Помещать туда студентов без группы. M>В таблицу `group` добавить колонку с типом группы (обычная или имеет особый смысл).
Один недостаток у этого решения все же есть.
Курс , на котором студенты, достаточно поместить в `group`, так как вся группа на одном курсе.
Для этой виртуальной группы так не получится. Придется курс помещать в student, а там это лишнее, в общем-то. Для студентов внутри группы он не нужен.
Можно создать не одну, а 4 или 5 виртуальных групп, каждая по своему курсу. В этом даже какая-то логика есть — студенты, вышедшие из общего процесса на таком-то курсе. Если кто-то из них вернется даже через несколько лет — вся информация на месте. Вышел из общего процесса на 3 курсе, туда и надо вернуть. Так сказать, заморозка участия на неопределенный срок.
With best regards
Pavel Dvorkin
Re[15]: и еще один вопрос по реляционной структуре
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Qulac, Вы писали:
Q>>Вот так например:
PD><skipped>
PD>Ну не знаю. Может быть, это и будет работать, но нужно серьезное тестирование. PD>И где тут базовая (в терминах предыдущих твоих постингов) таблица ? Или она и есть students_sets ?
Да.
PD>В общем, рекомендовать это студентам я бы не стал. ИМХО слишком тяжелая артиллерия для , в общем-то, простой ситуации. В конце концов 2 FK от студента на группу и факультет хоть и не очень хорошо с точки зрения канонов, но терпимо.
Применять это на практике или нет — это уже другой вопрос, но способ есть для случаев когда у сущности могут быть взаимоисключающие связи с другими сущностями.
PD>Ну и концептуально мне это решение не нравится. Получается, что таблицы факультет и группа — братья и оба "потомки" от базовой. А по смыслу все же факультет : группа == parent:child. И не стоит ради того, чтобы решить локальную проблему, портить структуру .
Собственно это и есть наследование поведения — и факультет и группа могут содержать в себе студентов, т.е. у них есть общность.
PD>А вот это решение вообще снимает все проблемы легко и изящно
PD>https://rsdn.org/forum/db/8843919.1
Мое дело было предложить вариант решения. Вообще как известно используя реляционную модель можно смоделировать любую структуру данных в нормальной форме. Как это сделать в этом случае?
Q>Собственно это и есть наследование поведения — и факультет и группа могут содержать в себе студентов, т.е. у них есть общность.
Ну в общем-то да. В императивном языке явно напрашивается interface StudentHolder и Group и Faculty extends его.
А в то же время, если допустить, что только Group может иметь студентов, то Faculty может его и не имплементировать, что ничему не помешает, так как косвенно итерацией по группам мы все их получим.
Ну а если все же и сам Faculty может их иметь (то есть без виртуальной группы), то не скажу, что и это решение мне нравится.
Хотя...
Рассмотрим аналогичный пример. Товары в магазине в категориях (мясные, молочные, растительные...). Пусть каждый товар принадлежит только одной категории. Но есть товары, ни в одну категорию не входящие.
Тут возражений концептуальных нет.
А по сути то же самое.
Q>Мое дело было предложить вариант решения. Вообще как известно используя реляционную модель можно смоделировать любую структуру данных в нормальной форме. Как это сделать в этом случае?
Не знаю, я не большой специалист в теории БД и тем более в реляционной алгебре. Может, другие скажут ?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Пусть та же система, что и тут
Предлагаю подумать насчет хранения истории изменения принадлежности студента к группе.
Многие вопросы, даже еще не озвученные, снимутся.
Но, как обычно бывает, возникнут другие )))
PD>Можно создать не одну, а 4 или 5 виртуальных групп, каждая по своему курсу. В этом даже какая-то логика есть — студенты, вышедшие из общего процесса на таком-то курсе. Если кто-то из них вернется даже через несколько лет — вся информация на месте. Вышел из общего процесса на 3 курсе, туда и надо вернуть. Так сказать, заморозка участия на неопределенный срок.
Почему бы и нет — по одной виртуальной группе на каждый курс каждого факультета.
Кстати вариант с таблицами отношений (student-group, group-faculty) мне кажется более гибким, т.к. позволяет при необходимости поместить студента в несколько групп.
Но виртуальные группы там тоже будут нужны для связи студента без группы и факультета.
Здравствуйте, swimmers, Вы писали:
S>Предлагаю подумать насчет хранения истории изменения принадлежности студента к группе. S>Многие вопросы, даже еще не озвученные, снимутся.
Несомненно. Если вводить историю (версионность), то ее надо делать не только для принадлежности студента к группе, но и для самих групп.
Например, когда я учился, номер группы формировался так
код_факультета последняя_цифра_года_поступления номер_группы_в_этом году.
Поэтому, скажем, 822 группа — это и группа набора 1922 года, и 1932 года, ... 2022 года.
А еще после 3 курса все группы ликвидировали и распределили по новым группам в соответствии со специализацией
Были группы 821-823, а стали 821-825, при этом общего у прежней 822 и новой 822 ничего не было, хотя какие-то студенты и были до в 822 и оказались после в 822.
Ну а если дальше пойти — переименования, слияния и разделения факультетов...
Здравствуйте, m2user, Вы писали:
M>Кстати вариант с таблицами отношений (student-group, group-faculty) мне кажется более гибким, т.к. позволяет при необходимости поместить студента в несколько групп.
Для student-group вполне согласен. Более того, порой он единственно возможный, например, для спортшколы, где вполне реально, что кто-то входит в 2+ секции
Для group-faculty — сомневаюсь. Не могу представить группу, принадлежащую 2 факультетам одновременно.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>В итоге у студента должно быть 2 FK — на группу и факультет. Но группа имеет FK на факультет. Получается, что студент фактически имеет 2 FK на факультет — один явно, а другой косвенно, через свой FK на группу и FK группы на факультет.
Дополню, что студет может одновременно учиться на двух (и более) факультетах.
В нашем пединституте можно было например паралельно с физматом обучаться на инязе.
Закон разрешает студентам одновременно осваивать несколько образовательных программ.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Но это уже совсем другая задача.
Ты бы начал с формализации требований/ТЗ/спецификаций (назови как хочешь) для твоей учебной задачи -- основные моменты без растекания.
Например, если в требованиях будет зафиксированно, что студент может быть только в одной группе и историю переводов из группы в группу, или с факультета на факультет хранить не надо, то и вопросов меньше.
Да и проверять и оценивать работы студентов будет проще.
Здравствуйте, paucity, Вы писали:
P>Ты бы начал с формализации требований/ТЗ/спецификаций (назови как хочешь) для твоей учебной задачи -- основные моменты без растекания.
P>Например, если в требованиях будет зафиксированно, что студент может быть только в одной группе и историю переводов из группы в группу, или с факультета на факультет хранить не надо, то и вопросов меньше.
Да, ты прав, я как-то не подумал. Надо было с самого начала объяснить, что это модельная учебная задача, а вовсе не для production.
Исправляюсь.
В общем, есть у меня учебное упражнение по основам SQL а потом MyBatis и Hibernate.
Задача простая — факультет, группы, студенты, предметы
Цель — освоить SQL и остальное. PK, FK, WHERE всякие, JOIN и т.п. В общем, основы SQL , начальный курс. Без триггеров и SP.
Ну и many :1 (student : group) и many:many (group:subject).
Институт я в этой модели опустил. Лес факультетов с группами и студентами в них. Естественно, только текущее состояние, никакой истории.
А с другой стороны, правила тут должны быть именно те, что в реальности. Предметная область студентам очень уж хорошо знакома
И вот я подумал, не расширить ли задачу, добавив институт. В исходной задаче принадлежность студентов замалчивается. Они члены групп или не члены, а те, что не члены, явно ни чему не принадлежат.
Ну и возникли 2 вопроса. Первый — про единственную запись в таблице институт, а вторая — к чему принадлежат студенты, не входящие в группы.
Здравствуйте, sergeya, Вы писали:
S>Закон разрешает студентам одновременно осваивать несколько образовательных программ.
Да, верно, я как-то забыл об этом.
Лет 25 назад был у меня один студент, мой курсовик. Доучился до 3 курса, а потом сообщил мне, что он поступил еще на заочное на юрфак.
Я ему сказал, что не получится у него, времени не хватит. Он ответил, что хватит.
Через полгода мы встретились, и он сказал : "Вы были правы". Пришел он забрать документы.
Больше я его не видел.
PD>пусть есть таблица institute с одной строкой. Или как-то иначе. Это здесь не обсуждаем.
PD>Есть факультеты. Таблица faculty с FK (или без него, как хотите) на institute
PD>На факультете есть группы. Таблица `group` с FK на faculty.
PD>А еще есть студенты. Таблица student и вот тут вопрос
Один и тот же человек может одновременно учиться на разных факультетах. Дневной + заочка. Или на одном, но на разных специальностях.
Поэтому связь студента с факультетом и группой через промежуточную таблицу. Там связь M:N.
Да каждый человек имеет сслылку на хотя бы 1 факультет (обязательно). И возможно на группу, а если в академе, то не имеет ссылки на группу, только на факультет.
И еще нужно разрулить когда он на одно и том же факультете учится на одной специальности, а на 2 а академе.
Нужен отдельной таблице список студентов в академе получается.
Итого
Факультеты
Группы
Академы
Студенты.
И таблицы для связей всего этого. Как-то так.
Еще комментарий по первоначальному варианту. С начала нужно разобраться: А есть ли тут проблема вообще? Большинство сделают так: один fk у студента постоянно указывает на факультет, в который он зачислен, второй на группу если он в ней учится. Казалось бы тут есть избыточность: студент имеет имеет две связи с факультетом: одну прямую, вторую через группу. Но, это разные ассоциации. Что бы это определить нужно попытаться им дать названия и(или) назвать роли сущностей участвующих в ассоциации. В первом случае у студента роль "зачисленный", а во втором "учащийся". Группу можно считать сущностью-ассоциацией. Еще к этому есть инвариант: студент может учиться только в той группе, которая связана с факультетом в который он зачислен. Можно привести и другие примеры когда между сущностями могу существовать более чем одной ассоциации: между мужчиной и женщиной могут существовать две связи: муж и жена, начальник — подчиненный(встречал такое в жизни). Надеюсь понятно изложил.
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 до всего двух, а это явный выигрыш!)
Здравствуйте, Pavel Dvorkin, Вы писали: PD>На императивном языке можно было бы ограничиться одной ссылкой на некий интерфейс или базовый класс. Если студент член группы, то на Group (а она на Faculty), если не член — прямо на Faculty. Может, и не лучшее решение, но возможное. А тут одним FK можно обойтись ?
Одним — нет, нельзя. Но можно получить гарантию непротиворечивости.
Первый FK — композитный, Student(GroupID, FacultyID) -> Group(ID, FacultyID)
Второй FK — простой, Student(FacultyID) -> Faculty(ID)
Первый предотвращает возможность попасть в группу с чужого факультета. Второй предотвращает возможность попасть на несуществующий факультет при пустой группе. https://www.db-fiddle.com/f/4m6HA2zSzdKCE4bKSVwEtu/0
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Одним — нет, нельзя. Но можно получить гарантию непротиворечивости. S>Первый FK — композитный, Student(GroupID, FacultyID) -> Group(ID, FacultyID) S>Второй FK — простой, Student(FacultyID) -> Faculty(ID) S>Первый предотвращает возможность попасть в группу с чужого факультета. Второй предотвращает возможность попасть на несуществующий факультет при пустой группе.
То есть когда студент становится студентом вне группы, Student.GroupID ставится в NULL ? А что тогда получится с первым FK ?