Каков наилучший способ разработки этой конкретной проблемы с базой данных / SQL? - PullRequest
5 голосов
/ 21 октября 2010

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

У вас есть набор действий. Это то, что нужно сделать - прославленный список TODO. Любой данный вид деятельности может быть назначен сотруднику.

У каждого действия также есть объект, для которого это действие должно быть выполнено. Такими действиями являются либо контакт (личность), либо клиент (бизнес). Каждое действие будет иметь контакт или клиента, для которого будет выполнено действие. Например, действие может быть «Отправить карту благодарности Spacely Sprockets (клиент)» или «Отправить маркетинговую литературу Тони Алмейде (контакт)».

Из этой структуры нам нужно иметь возможность запрашивать все действия, которые должен выполнять данный сотрудник, перечисляя их в одном отношении, которое будет выглядеть примерно так в простейшей форме:

-----------------------------------------------------
| Activity | Description    | Recipient of Activity |
-----------------------------------------------------

Идея здесь состоит в том, чтобы избежать двух столбцов для Контакта и Клиента с одним из них нулевым.

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

Таким образом, вопрос заключается в следующем: каков «правильный» дизайн базы данных и как бы вы запросили ее для получения запрашиваемой информации?

Ответы [ 11 ]

9 голосов
/ 21 октября 2010

Звучит как базовое отношение многие ко многим, и я бы смоделировал его как таковой.

alt text

4 голосов
/ 21 октября 2010

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

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

  1. Используйте два столбца, один NULL, чтобы разрешить ссылочную целостность дляwork.

  2. Создайте промежуточную таблицу ActivityContacts с собственным PK и двумя столбцами, один NULL, для указания на клиента или контакт.Это позволяет вам создать «чистую» систему Activity, но помещает уродство в эту промежуточную таблицу.(Это дает возможное преимущество, заключающееся в том, что оно позволяет вам ограничить цель действий людьми, добавленными в промежуточную таблицу, если это является преимуществом для вас).

  3. Переноситьнедостаток оригинального дизайна в системе Деятельности и (я здесь кусаю язык) имеют параллельные таблицы ContactActivity и CustomerActivity.Чтобы найти все назначенные сотруднику задачи, объедините эти две таблицы в одну в VIEW.Это позволяет поддерживать ссылочную целостность, не требует использования столбцов NULL и предоставляет источник, из которого можно получить отчеты.

4 голосов
/ 21 октября 2010

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

Таблица действий должна иметь внешние ключи ContactID, CustomerID

Для отображения операцийдля работника:

SELECT ActivityName, ActivityDescription, CASE WHEN a.ContactID IS NOT NULL THEN cn.ContactName ELSE cu.CustomerName END AS Recipient
FROM activity a
LEFT JOIN contacts cn ON a.ContactID=cn.ContactID
LEFT JOIN customers cu ON a.CustomerID=cu.CustomerID
2 голосов
/ 21 октября 2010

Если я правильно понял случай, Recipients - это обобщение клиентов и контактов.
Шаблон проектирования Gen-spec хорошо понятен.

Вопрос моделирования данных

2 голосов
/ 21 октября 2010

Вот мой пример:

В основном вам нужно, чтобы действия были связаны с 1 (контакт или клиент) и 1 сотрудником, который должен быть ответственным лицом за действие.Обратите внимание, что вы можете обрабатывать ссылочные ограничения в такой модели.

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

alt text

1 голос
/ 21 октября 2010

alt text

1 голос
/ 21 октября 2010

У вас будет что-то вроде следующего:

Activity | Description | Recipient Type

Где Recipient Type является одним из Contact или Customer

Затем вы выполняете оператор выбора SQL следующим образом:
Select * from table where Recipient_Type = 'Contact';

Я понимаю, что нужно больше информации.

Нам потребуется дополнительная таблица, представляющая получателей (контакты и клиенты):

Эта таблица должна выглядеть следующим образом:

ID | Name| Recipient Type

Recipient Type будет ключевой ссылкой на таблицу, первоначально упомянутую ранее в этом посте. Конечно, нужно будет проделать работу для обработки каскадов между этими таблицами, в основном при обновлении и удалении. Итак, чтобы быстро резюмировать:

Recipients.Recipient_Type - от FK до Table.Recipient_Type

0 голосов
/ 29 октября 2010

Я бы пересмотрел это определение Клиента и Контакта.Клиент может быть или человеком или бизнесом, правильно?В Бразилии существуют термины «pessoa jurídica» и «pessoa física», которые в прямом (и бессмысленном) переводе становятся «юридическим лицом» (бизнесом) и «физическим лицом» (физическим лицом).Google предложил лучший перевод: «юридическое лицо» и «физическое лицо».

Итак, мы получаем личную таблицу и имеем таблицы «LegalEntity» и «Individual» (если есть достаточные атрибуты, чтобы оправдать это - здесь есть много).И получатель становится таблицей FK to Person.

А куда делись контакты?Они становятся таблицей, которая ссылается на человека.Поскольку контакт - это человек, который является контактом другого человека (пример: моя жена является моим зарегистрированным контактом с некоторыми компаниями, которые я являюсь клиентом).У людей могут быть контакты.

Примечание. Я использовал слово «Персона», но вы можете назвать его «Клиент», чтобы назвать эту базовую таблицу.

0 голосов
/ 21 октября 2010

Смоделируйте другой объект: ActivityRecipient, который будет унаследован от ActivityRecipientContact и ActivityRecipientCustomer, который будет содержать надлежащий идентификатор клиента / контакта.

Соответствующими таблицами будут:

Table: Activities(...., RecipientID)

Table: ActivityRecipients(RecipientID, RecipientType)

Table: ActivityRecipientContacts(RecipientID, ContactId, ...,ExtraContactInfo...)

Table: ActivityRecipientCustomers(RecipentID, CustomerId, ...,ExtraCustomerInfo...)

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

0 голосов
/ 21 октября 2010
Actions
Activity_ID | Description | Recipient ID
-------------------------------------
11    | Don't ask questions | 0
12    | Be cool    | 1

Activities
ID | Description
----------------
11  | Shoot
12  | Ask out

People
ID | Type | email | phone | GPS |....
-------------------------------------
0  | Troll | troll@hotmail.com | 232323 | null | ...
1  | hottie | hottie@hotmail.com | 2341241 | null | ...


select at.description,a.description, p.* from Activities at, Actions a, People p
where a."Recipient ID" = p.ID 
  and at.ID=a.activity_id

result:

Shoot | Don't ask questions | 0 | Troll | troll@hotmail.com | 232323 | null | ...  
Ask out | Be cool | 1 | hottie | hottie@hotmail.com | 2341241 |null | ...
...