Проектирование базы данных SQL Server 2005 - отношения «многие ко многим» с иерархией - PullRequest
6 голосов
/ 19 марта 2010

Примечание

Я полностью переписал свой оригинальный пост, чтобы лучше объяснить проблему, которую пытаюсь понять. Я постарался максимально обобщить проблему.

Кроме того, я благодарен оригинальным людям, которые ответили. Надеюсь, этот пост прояснит ситуацию.

Context

Короче говоря, я изо всех сил пытаюсь понять, как лучше всего спроектировать небольшую базу данных, чтобы обрабатывать (как мне кажется,) множественные отношения «многие ко многим».

Представьте себе следующий сценарий для организационной структуры компании:

             Textile Division                    Marketing Division
                    |                                     |
          ----------------------               ----------------------
          |                    |               |                    |
       HR Dept           Finance Dept        HR Dept           Finance Dept
          |                    |               |                    |
      ----------          ----------       ----------           ---------
     |          |         |        |       |        |           |       |
  Payroll     Hiring    Audit     Tax   Payroll   Hiring      Audit  Accounts
     |          |         |        |       |        |           |       |
    Emps      Emps       Emps     Emps    Emps     Emps        Emps    Emps    

NB: Emps обозначает список работников, работающих в этой области

Когда я впервые начал заниматься этим вопросом, я создал четыре отдельные таблицы:

  1. Divisions -> Текстиль, маркетинг (PK = DivisionID)
  2. Departments -> HR, финансы (PK = DeptID)
  3. Functions -> Расчет заработной платы, наем, аудит, налоги, счета (PK = FunctionID)
  4. Employees -> Список всех сотрудников (PK = EmployeeID)

Проблема, как я вижу, состоит в том, что существует множество отношений «многие ко многим», то есть многие отделы имеют много отделов, а многие функции имеют много отделов.

Вопрос

Предоставляя структуру базы данных выше, предположим, что я хотел сделать следующее:

  • Получить всех сотрудников, которые работают в функции расчета заработной платы отдела маркетинга

Для этого мне нужно иметь возможность различать два отдела расчета заработной платы, но я не уверен, как это можно сделать?

Я понимаю, что мог бы создать таблицу «Связь / соединение» между отделами и функциями, чтобы можно было узнать, какие функции в каких отделах есть. Тем не менее, мне все равно нужно было бы дифференцировать отдел, к которому они принадлежат.

Усилия по исследованию

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

Ответы [ 7 ]

2 голосов
/ 25 марта 2010

Основываясь на обновленном сообщении и делая некоторые (довольно очевидные) предположения, основанные на используемых именах, я придумываю следующее.Существует четыре объекта:

  • Отделы
  • Отделы
  • Функции
  • Объекты

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

  • Опция A1: существует основной список функций.Каждый отдел может выполнять (или выполнять) одну или несколько функций, и эту функцию может выполнять не только отдел.
  • Опция A2: Функции «принадлежат» департаментам.Никакая функция не может выполняться двумя или более отделами.(Похоже, что это так, поскольку в отделе кадров есть отдел расчета и найма, а в отделе финансов - аудит, налоги и счета.)

  • Функции выполняются отделами для (вкл.от имени) подразделения.(Отдел кадров занимается расчетами заработной платы и наймом для текстильных и маркетинговых подразделений; отдел финансов занимается аудитом и налогами - но не для счетов - для текстильного отдела, а для аудита и счетов - но не для налогов - для отдела маркетинга.) Возможно, немногоболее точно, отделы выполняют выбранные функции для выбранных подразделений, с которыми они связаны, и эта связь определяется их выполнением этой функции.

  • Помимо выполнения функций, появляетсяне будет никаких отношений между отделами и отделами.Между ними нет иерархических отношений, так как одно не «владеет» или не содержит другого.

Это приводит к следующим примерным таблицам:

--  Division  -----
DivisionId  (primary key)

--  Department  ---
DepartmentId  (primary key)

--  Function  -----  (assumes option A2)
FunctionId   (primary key)
DepartmentId (foreign key, references Department)

--  DivisionFunctions  ----
DivisionId  (First column of compound primary key)
FunctionId  (Second column of compound primary key)

(При желании можно добавить суррогатный ключ для уникальной идентификации каждой строки, но DivisionId + FunctionId будет работать.)

Здесь недостаточно материала, чтобы полностью описать, как "сотрудники" вписываются вмодель.Учитывая, что сотрудники выполняют работу функций: может ли сотрудник выполнять работу более чем одной функции или они выполняют только одну функцию?Выполняет ли сотрудник работу функции независимо от подразделения, для которого он выполняется, или ему поручено выполнять работу для одного или нескольких подразделений?Здесь есть два очевидных варианта, хотя возможны и более сложные варианты:

  • Вариант B1: сотрудники выполняют работу по одной или нескольким функциям в отделах и выполняют эту работу для всех подразделений, которым требуется эта функция этого отдела.
  • Опция B2: сотрудникам назначается выполнять определенную функцию для определенного подразделения.

С учетом этого таблицы могут выглядеть следующим образом:

--  Employee  -----  (assumes option B1)
EmployeeId    (primary key)
DepartmentId  (foreign key, references Department)

--  EmployeeFunction  -----  (assumes option B1)
EmployeeId  (First column of compound primary key)
FunctionId  (Second column of compound primary key)

... и, следовательно, все сотрудники, которые могут выполнять функцию, будут выполнять ее для всех подразделений, которым она требуется.Или

--  Employee  -----  (assumes option B2)
EmployeeId  (primary key)
DepartmentId  (foreign key, references Department)

--  EmployeeAssignment  -----  (assumes option B2)
EmployeeId  (foreign key, references Employee)
DivisionId  (first of two-column foreign key referencing DivisionFunctions)
FunctionId  (second of two-column foreign key referencing DivisionFunctions)

(Или вместо DivisionId и FunctionId включите необязательный суррогатный ключ из DivisionFunctions.) ... и, таким образом, сотрудники назначаются индивидуально для функций, выполняемых отделом для подразделения.

Но это все еще оставляет много вопросов «что если / когда»: сотрудники «принадлежат» к департаментам?Могут ли сотрудники принадлежать (работать) к нескольким отделам?Возможно, сотрудники относятся к подразделениям?Отслеживаете ли вы, какие функции может выполнять сотрудник, даже если он в настоящее время не выполняет его?Точно так же вы отслеживаете, в каком отделе работает сотрудник, даже если он в настоящее время находится «между функциями»?Если сотрудник может выполнять функции A и B, а подразделению требуются обе эти функции, может ли сотрудник назначаться для выполнения только A, а не B для этого подразделения?

Здесь необходимо провести дополнительное исследование требований,но я хотел бы думать, что это хорошее начало.

1 голос
/ 25 марта 2010

Поскольку вы «абедок», :), прежде чем пытаться чувствовать себя как дома при проектировании базы данных, нужно прочитать одну вещь о нормализации и полностью понять все нормальные формы вплоть до 5NF

Если вы хотите смоделировать это
1. отделения находятся в отделах
2. функции выполняются в отделах
3. сотрудники выполняют функции

и что не все функции выполняются во всех отделах, а также не во всех отделах во всех отделах, тогда вы должны хранить этот факт где-то.

При логическом проектировании присвойте своим таблицам описательные имена, чтобы некоторые отделы были в отделах

departments_in_divisions
candidate key: department, division

тогда у вас есть некоторые функции в некоторых отделах

functions_departments_divisions
candidate key: function, department, division
references: (department, division) in departments_divisions

тогда у сотрудников есть некоторые функции из некоторых отделов и отделов

employees_function_department_division
candidate key: employee, function, department, division
references: (function, department, division) in functions_departments_divisions

После (или до этого) у вас появятся еще 3 функции, отделы и отделы, в которых будут перечислены все возможные отделы, отделы и функции, на которые также будут ссылаться вышеуказанные таблицы (это может быть не полностью нормализовано).

Также имена объектов (таблиц) могут стать чем-то более подходящим для вас (только вы можете знать полную семантику модели ваших данных). Особенно, если вы заметили, что вам нужно присвоить им другие атрибуты (поля).

Значения для отделов, отделов и функций являются их названиями, в приведенном выше анализе искусственных идентификаторов еще нет. Вы можете представить их на следующем шаге, после логического моделирования, физического моделирования, или вы можете оставить естественные ключи. Если вы используете искусственные ключи, которые могут сократить использование составных ключей до максимума 2, но это затуманивает отношения и значение фактов, которые вы храните в своих таблицах. (Примером functionID может быть и идентификатор имени функции, или идентификатор функции, выполняемой в определенной комбинации подразделений / отделов - неясно, что это такое, и они не являются взаимозаменяемыми; вроде как разница между экземпляром и класс).

1 голос
/ 23 марта 2010

Вам нужны простые звезды отношения. Позиция (таблица фактов) содержит только идентификаторы связанных основных таблиц ( Отдел , Отдел и т. Д.). Это позволяет использовать любую комбинацию основных таблиц

Основные таблицы могут иметь простую иерархию, встроенную в каждую из них по мере необходимости. И может относиться друг к другу по мере необходимости. Но детали этого не влияют на запросы к Position

Вы можете сделать идентификаторы в Позиции Обнуляемыми для необязательных отношений

Вы можете добавить столбцы StartDate и EndDate в Положение , чтобы отслеживать изменения во времени

Простой пример этого:

SQL Table Diagram

1 голос
/ 19 марта 2010

Ну, вы бы не положили все это в один стол.Вы должны прочитать о нормализации данных и объединений.(И никогда не сохраняйте ничего в списке через запятую.)

Ни одна база данных не стоит ни малейшей проблемы при обработке миллиона записей, то есть крошечной базы данных.

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

0 голосов
/ 23 марта 2010

Возможно (вероятно) вам следует рассматривать отдел кадров текстильного отдела как отдел, отличающийся от отдела кадров отдела маркетинга.

0 голосов
/ 19 марта 2010

Обычно, когда я настраиваю БД, я придумываю, какие сущности мне нужны и как они связаны друг с другом (т. Е. Многие-один, один-один, ...). Что вы, кажется, сделали. Итак, затем я выясняю, что нужно каждой сущности. Например, Местоположение может иметь: locationid, address, ... Затем, Подразделения Предполагая, что у каждого есть одно местоположение для многих подразделений, у объекта подразделения может быть подразделение, locationid, информация, необходимая каждому подразделению. Таким образом, в принципе, если это отношение «один-много», например, одно местоположение для многих подразделений, вы можете просто указать идентификатор местоположения в таблице подразделений. Однако, если это отношение «многие-многие», вероятно, лучше иметь промежуточную таблицу для соединения двух, чтобы вам не нужно было иметь дублирующиеся записи с изменением только идентификатора.

0 голосов
/ 19 марта 2010

Попробуйте дать каждому объекту собственную таблицу, например,

//Table Structure
location
    locationId
    name

division
    divisionId
    name
    locationId (fk => location)

department
    deparmentId
    name
    divisionId (fk => division)

function
    functionId
    name
    departmentId(fk => department)

jobrole
    jobroleId
    name
    functionId

course
    courseID
    name

jobrole_course_requirement
    jobroleID
    courseID

employee
     employeeID
     name

employee_jobRole
     employeeID
     jobRoleId

emploeyee_course_attendance
     emploeyee_course_attendanceID
     emploeyeeID
     courseID
     dateAttended

И какой-то образец выбирает

// Get course requirements for an employee
select course.name 
  from course, 
       jobrole_course_requirement, 
       employee_jobRole
  where 
       employee_jobRole.employeeID = 123 and
       jobrole_course_requirement.JobRoleId = employee_jobRole.JobRoleId
       course.courseID = jobrole_course_requirement.courseID
...