Вопрос схемы базы данных - PullRequest
0 голосов
/ 08 апреля 2009

Мне трудно решить, как обрабатывать бизнес-требования в схеме базы данных. У меня есть много таблиц в базе данных, но есть только три, с которыми мне нужно иметь дело для этой проблемы: Курсы, ПерсоналКурсы и Персонал.

  • Курсы - это список курсов
  • Кадровая это список персонала
  • PersonnelCourses - это список курсов этот персонал взят .

На курсах есть колонка под названием Универсальная. Если курс универсален, это означает, что весь персонал должен пройти этот курс.

Мне нужно составить список всех универсальных курсов, которые персонал должен пройти , но единственный способ, которым я могу создать этот список, - это перекрестное / декартовое соединение:

выберите P.LastName, C.Name из курсов C, персонал P где универсальный = 1

После этого я хочу сделать левое соединение с PersonnelCourses, чтобы у меня был список всего персонала и курсов, которые они должны пройти, а также курсов, которые они прошли. Я думаю, что все было бы проще, если бы между персоналом и курсами было много-много таблиц Но если все сотрудники в любом случае будут находиться в этой средней таблице, разве это не избыточно?

Есть ли лучший способ справиться с этим?

Очень ценится,

Матф

Ответы [ 6 ]

3 голосов
/ 08 апреля 2009

Существует список курсов, которые каждый должен пройти. Почему бы просто не взять этот список и работать с ним, вместо того, чтобы повторять один и тот же список для каждой строки персонала? Я не понимаю, почему вы пытаетесь умножить свой набор результатов.

1 голос
/ 08 апреля 2009

Это тема Нормализация базы данных , на которой написаны книги и часть того, почему вы хотите это сделать, это DRY или не повторяйте себя.

Так что, чтобы ответить на ваш вопрос о лучшем способе - я бы ответил нет.

1 голос
/ 08 апреля 2009

Разве ваши PersonnelCourses не устанавливают отношения между многими людьми и курсами? Если это не так, то я не уверен, если это так ...

select *

from Personnel_Courses 
    inner join Person on... /*get the Person details*/
    inner join Courses on... /*get the Course details*/

where Course.Universal = 1 and Person.Id = @Id

скажет вам, какие универсальные курсы они прошли ...

, а затем

select *

from Courses

where Courses.Universal = 1 and Course.Id not in (
        select Course.Id from Personnel_Courses 
        inner join Person on... /*get the Person details*/
        inner join Courses on... /*get the Course details*/
        where Course.Universal = 1 and Person.Id = @Id
        )

дал бы вам универсальные курсы, которые они не посещали ...

Мне может быть проще сделать 2-й в вашем коде (Получить результаты первого запроса, сделать выбор из таблицы курса, чтобы получить все универсальные, а затем сделать сравнение ...)

0 голосов
/ 08 апреля 2009

Universal является двухзначным (логическим) атрибутом Course, верно? В этом случае подумайте о дальнейшей нормализации. Перепроектируйте так, чтобы UniversalCourse была таблицей, а не столбцом в Course. Эта таблица будет иметь один столбец, ссылающийся на курс. Чтобы найти все универсальные курсы, просто выберите все из этой таблицы. Теперь вы можете значительно сократить свое декартово соединение, поскольку вам нужно умножить Personnel только на таблицу UniversalCourse, исключив условие where Universal = 1.

0 голосов
/ 08 апреля 2009

Как насчет этого (используя существующую структуру)?

SELECT P.LastName, C.Name, 1 as Taken  
FROM Courses C   
  INNER JOIN PersonnelCourses PC ON (C.CourseID=PC.CourseID)  
  INNER JOIN Personnel P ON (P.PersonID=PC.PersonID)  
WHERE(C.Universal = 1)  

UNION  

SELECTP.LastName, C.name, 0 as Taken  
FROM Courses C, Personnel P   
WHERE (Universal = 1) and   
   NOT EXISTS(SELECT * FROM Courses C2 
             INNER JOIN PersonnelCourses PC2 ON (C.CourseID=PC.CourseID)
             INNER JOIN Personnel P2 ON (P.PersonID=PC.PersonID)
             WHERE (Universal = 1)  and 
                    (PC2.CourseID=C.CourseID) and       
                    (P2.PersonID=PC2.PersonID)
             )
0 голосов
/ 08 апреля 2009

Весь персонал не будет присутствовать в таблице кадров, только персонал, прошедший курсы.

Я думаю, с твоим дизайном все в порядке. Вам просто нужно настроить запрос, чтобы получить то, что вам нужно.

В подзапросе выведите курсы, пройденные персоналом. Затем во внешнем запросе выберите все курсы, которые должен пройти персонал, и выполните левое внешнее соединение с подзапросом.

Select a.CourseName, b.PersonName from Courses a, 
(select P.LastName, C.Name from Courses C, Personnel P, PersonnelCourses pc 
  c.courseid = pc.courseid and
  p.personnelid = pc.personnelid and
  c.Universal = 1)  b 
where
a.courseid += b.courseid order by courseid

Вероятно, было бы лучше отфильтровать по персоналу, если это для отчета. Таким образом, вы увидите все необходимые курсы, в том числе курсы на человека.

...