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

10

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

План состоит в том, чтобы иметь usersтаблицу ответственной в значительной степени только для входа на сайт ( name, emailа passwordстолбцы плюс один или два других , таких , как я ли они были утверждены, и updated_at), а также дополнительные таблицы для каждого из соответствующих типов пользователей , которые каждый имеют свой уникальный набор столбцов. Например, только у актеров будет столбец этнической принадлежности, только у директоров - столбец биографии, и только сценаристы должны будут указывать свое местоположение. Однако, поскольку раньше я не управлял базой данных такой сложности, мне интересно, как организовать несколько аспектов:

Во-первых, пользователи могут быть любыми или любой комбинацией указанных выше типов. Поэтому я понимаю, что мне нужно что-то вроде (например) director_userтаблицы с director_idи user_idстолбцами. Тогда этого будет достаточно, чтобы можно было фильтровать всех пользователей по типу роли и т. Д.?

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

веризм
источник

Ответы:

14

Согласно моей интерпретации вашего описания бизнес-контекста, представляющего интерес, вы имеете дело со структурой подтип 1 подтипа, в которой (а) актер , директор и писатель являются подтипами сущностей (b) Person , их надтипами сущностей и (c) указанные подтипы не являются взаимоисключающими.

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

  • […] Дополнительные таблицы для каждого из соответствующих типов пользователей, каждый из которых имеет свой уникальный набор столбцов.

  • […] Есть только четыре пользовательских типа, которые имеют отношение к делу. Существует внешняя вероятность того, что это число может увеличиться, но вероятность низкая - и в таком случае будет очень небольшое число.

Я подробно остановлюсь на всех этих аспектах и ​​некоторых других критических факторах в следующих разделах.

Бизнес правила

Чтобы сначала определить соответствующую концептуальную схему, которую можно использовать в качестве последующей ссылки, чтобы вы могли адаптировать ее, чтобы удостовериться, что она соответствует точным информационным требованиям, я сформулировал некоторые бизнес-правила, которые имеют особое значение:

  • Человек может проводить один-два-три-или (то есть, один-к-все) Роль 2 . Другими словами, человек может быть
    • Актер и
    • директора и
    • Writer .
  • Человек может войти через нулевой или один- UserProfile .
  • Актер обеспечивает один-два или три- адрес 3 .
  • Актер группируется по одной этничности .
  • Этничность группы нуль-один-или-многие актеры .
  • Writer основан на одном участке .
  • Расположение является основой нулевого один-или-больше писателей .

Описательная схема IDEF1X

Затем я создал диаграмму IDEF1X 4 , показанную на рисунке 1 , которая группирует все приведенные выше формулировки вместе с другими соответствующими правилами:

Рисунок 1 - Диаграмма IDEF1X для ролей человека и контактных данных в кино

Как показано, супертип Person (i) имеет свой собственный блок, (ii) обладает свойствами или атрибутами, которые применяются ко всем подтипам, и (iii) представляет линии, которые связывают его с полями каждого подтипа.

В свою очередь, каждый подтип (а) появляется в своем собственном выделенном поле, и (б) содержит исключительно свои применимые свойства. Первичный ключ супертипа PersonId переносит 5 в подтипы с именами ролей 6 ActorId , DirectorId и WriterId соответственно.

Кроме того, я избегал связывать Person с типом сущности UserProfile , что позволяет отделять все их контекстные значения, ассоциации или отношения и т. Д. Свойство PersonId было перенесено в UserProfile с именем роли UserId .

Вы заявляете в теле вопроса, что

И все актеры должны будут включать хотя бы один URL для любого из своих онлайн-профилей; в настоящее время есть три, которые они могут включать, но это число может увеличиться.

… Таким образом, URL является самостоятельным типом сущности и напрямую связан с подтипом Actor в соответствии с этой цитатой.

И в комментариях вы указываете, что

[…] У актера будет выстрел в голову (фотография), в то время как у писателя не будет […]

… Затем, среди других функций, я включил Headshot в качестве свойства типа объекта Actor .

Что касается типов сущностей Ethnicity и Location , они, конечно, могут повлечь за собой более сложные организации (например, Актер может принадлежать к одной, двум или более различным этническим группам в разных пропорциях, а Writer может основываться на месте, которое требует записи. страна, административный район, округ и т. д.), но похоже, что потребности вашего бизнес-контекста успешно покрываются смоделированными здесь структурами.

Естественно, вы можете внести столько корректировок, сколько необходимо.

Иллюстративный логический дизайн SQL-DDL

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

-- You should determine which are the most fitting 
-- data types and sizes for all your table columns 
-- depending on your business context characteristics.

-- Also, you should make accurate tests to define the 
-- most convenient INDEX strategies based on the exact 
-- data manipulation tendencies of your business needs.

-- As one would expect, you are free to utilize 
-- your preferred (or required) naming conventions. 

CREATE TABLE Person ( -- Represents the supertype.
    PersonId       INT      NOT NULL,
    FirstName      CHAR(30) NOT NULL,
    LastName       CHAR(30) NOT NULL,
    BirthDate      DATE     NOT NULL,
    GenderCode     CHAR(3)  NOT NULL,
    TwitterProfile CHAR(30) NOT NULL,
    PhoneNumber    CHAR(30) NOT NULL,
    EmailAddress   CHAR(30) NOT NULL,  
    CreatedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT Person_PK  PRIMARY KEY (PersonId),
    CONSTRAINT Person_AK1 UNIQUE ( -- Composite ALTERNATE KEY.
        FirstName,
        LastName,
        GenderCode,
        BirthDate
    ),
    CONSTRAINT Person_AK2 UNIQUE (TwitterProfile), -- ALTERNATE KEY.
    CONSTRAINT Person_AK3 UNIQUE (EmailAddress)    -- ALTERNATE KEY.
);

CREATE TABLE Ethnicity ( -- Its rows will serve a “look-up” purpose.
    EthnicityId     INT      NOT NULL,
    Name            CHAR(30) NOT NULL,  
    Description     CHAR(30) NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    -- 
    CONSTRAINT Ethnicity_PK PRIMARY KEY (EthnicityId),
    CONSTRAINT Ethnicity_AK UNIQUE      (Description)   
);

CREATE TABLE Actor ( -- Stands for one of the subtypes.
    ActorId         INT      NOT NULL, -- Must be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
    Headshot        CHAR(30) NOT NULL, -- May, e.g., contain a URL indicating the path where the photo file is actually stored. 
    EthnicityId     INT      NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    -- 
    CONSTRAINT Actor_PK            PRIMARY KEY (ActorId),
    CONSTRAINT ActorToPerson_PK    FOREIGN KEY (ActorId)
        REFERENCES Person (PersonId),
    CONSTRAINT ActorToEthnicity_PK FOREIGN KEY (EthnicityId)
        REFERENCES Ethnicity (EthnicityId)   
);

CREATE TABLE Director ( -- Denotes one of the subtypes
    DirectorId      INT       NOT NULL, -- Must be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
    Bio             CHAR(120) NOT NULL,  
    Etcetera        CHAR(30)  NOT NULL,
    CreatedDateTime DATETIME  NOT NULL,
    -- 
    CONSTRAINT Director_PK         PRIMARY KEY (DirectorId),
    CONSTRAINT DirectorToPerson_PK FOREIGN KEY (DirectorId)
        REFERENCES Person (PersonId)   
);

CREATE TABLE Country (
    CountryCode     CHAR(2)  NOT NULL,
    Name            CHAR(30) NOT NULL,  
    CreatedDateTime DATETIME NOT NULL,
    -- 
    CONSTRAINT Country_PK PRIMARY KEY (CountryCode),
    CONSTRAINT Country_AK UNIQUE      (Name)   
);

CREATE TABLE Location ( -- Its rows will serve a “look-up” purpose.
    CountryCode     CHAR(2)  NOT NULL,
    LocationCode    CHAR(3)  NOT NULL,
    Name            CHAR(30) NOT NULL,  
    CreatedDateTime DATETIME NOT NULL,
    -- 
    CONSTRAINT Location_PK PRIMARY KEY (CountryCode, LocationCode),
    CONSTRAINT Location_AK UNIQUE      (CountryCode, Name)   
);

CREATE TABLE Writer ( -- Represents one of the subtypes.
    WriterId        INT      NOT NULL, -- Must be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
    CountryCode     CHAR(2)  NOT NULL,
    LocationCode    CHAR(3)  NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    -- 
    CONSTRAINT Writer_PK           PRIMARY KEY (WriterId),
    CONSTRAINT WriterToPerson_PK   FOREIGN KEY (WriterId)
        REFERENCES Person (PersonId),
    CONSTRAINT WriterToLocation_PK FOREIGN KEY (CountryCode, LocationCode)
        REFERENCES Location (CountryCode, LocationCode)  
);

CREATE TABLE UserProfile (
    UserId          INT      NOT NULL, -- Must be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
    UserName        CHAR(30) NOT NULL,
    Etcetera        CHAR(30) NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    -- 
    CONSTRAINT UserProfile_PK PRIMARY KEY (UserId),
    CONSTRAINT UserProfile_AK UNIQUE      (UserName), -- ALTERNATE KEY.
    CONSTRAINT UserProfileToPerson_PK FOREIGN KEY (UserId)
        REFERENCES Person (PersonId)    
);

CREATE TABLE URL (
    ActorId       INT      NOT NULL,
    Address       CHAR(90) NOT NULL,
    Etcetera      CHAR(30) NOT NULL,
    AddedDateTime DATETIME NOT NULL,
    -- 
    CONSTRAINT URL_PK        PRIMARY KEY (ActorId, Address), -- Composite PRIMARY KEY.
    CONSTRAINT URLtoActor_FK FOREIGN KEY (ActorId)
        REFERENCES Actor (ActorId)
);

Таким образом, (1) каждый сингулярный аспект логического макета выше несет очень точное значение из (2) особой особенности деловой среды интереса 7 -в согласия с духом реляционной базы от доктора Эдгара Франка Кодда -, потому что:

  • Каждая базовая таблица представляет отдельный тип объекта.
  • Каждый столбец обозначает одно свойство соответствующего типа объекта.
  • Определенный тип данных фиксирован для каждого столбца , чтобы гарантировать, что все содержащиеся в нем значения принадлежат конкретному и правильно разделенному набору множеству a, будь то INT, DATETIME, CHAR и т. Д. (И будем надеяться, что MySQL наконец-то включит DOMAIN поддержка в ближайшем будущем).
  • Несколько ограничений настраиваются (декларативно), чтобы гарантировать, что утверждения в виде строк, сохраняемых во всех таблицах, соответствуют бизнес-правилам, определенным на концептуальном уровне.
  • Каждая строка предназначена для передачи четко определенной семантики, например, Personстрока читается

    Лицо, идентифицированное PersonId, rвызывается по имени FirstName, sа LastName tрождено в BirthDate u, имеет GenderCode v, твиты в TwitterProfile w, достигается через PhoneNumber x, связывается через EmailAddress yи регистрируется в CreatedDateTimez .

Наличие такого макета, безусловно, выгодно, так как вы можете получить новые таблицы (например, операции SELECT, которые собирают столбцы из нескольких таблиц с помощью предложения JOIN), которые - последовательно - также несут очень точное значение (см. Раздел под названием «Взгляды» ниже).

Стоит отметить, что в этой конфигурации (i) строка, представляющая экземпляр подтипа, идентифицируется (ii) тем же значением PRIMARY KEY, которое отличает строку, обозначающую вхождение дополнительного супертипа. Таким образом, более чем уместно отметить, что

  • (a) прикрепление дополнительного столбца для хранения сгенерированных системой и назначенных системой суррогатов 8 - (b) таблицы, обозначающие подтипы, (c) совершенно излишни .

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

Взгляды

Чтобы «извлечь», например, всю информацию, которая соответствует актеру , директору или автору записи , вы можете объявить некоторые представления (т. Е. Производные или выражаемые таблицы), чтобы вы могли ВЫБРАТЬ непосредственно из одного ресурса без необходимости записывать касательно СОЕДИНЕНИЯ каждый раз; Например, с представленной ниже ПРОСМОТР вы можете получить «полную» информацию об актере :

--
CREATE VIEW FullActor AS

    SELECT P.FirstName,
           P.Lastname,
           P.BirthDate,
           P.GenderCode,
           P.TwitterProfile,
           P.PhoneNumber,
           P.EmailAddress,
           A.Headshot,
           E.Name AS Ethnicity
         FROM Person P
         JOIN Actor A
           ON A.ActorId     = P.PersonId
         JOIN Ethnicity E
           ON E.EthnicityId = A.EthnicityId;
--

Конечно, вы можете использовать аналогичный подход для получения «полной» информации о директоре и писателе :

--
CREATE VIEW FullDirector AS

    SELECT P.FirstName,
           P.Lastname,
           P.BirthDate,
           P.GenderCode,
           P.TwitterProfile,
           P.PhoneNumber,
           P.EmailAddress,
           D.Bio,
           D.Etcetera
         FROM Person P
         JOIN Director D
           ON D.DirectorId = P.PersonId; 

--
CREATE VIEW FullWriter AS

    SELECT P.FirstName,
           P.Lastname,
           P.BirthDate,
           P.GenderCode,
           P.TwitterProfile,
           P.PhoneNumber,
           P.EmailAddress,
           L.Name AS Location,
           C.Name AS Country
         FROM Person P
         JOIN Writer W
           ON W.WriterId     = P.PersonId
         JOIN Country C
           ON C.CountryCode  = W.CountryCode
         JOIN Location L
           ON L.LocationCode = W.LocationCode;   
--

Я разместил все операторы DDL и представления DML, которые здесь обсуждались в этом скрипте SQL, работающем на MySQL 5.6, чтобы вы могли видеть и тестировать их «в действии».


Сноски

1 В некоторых концептуальных методах моделирования ассоциации супертип-подтип упоминаются как отношения суперкласс-подкласс .

2 Хотя вы упоминаете, что на самом деле существует больше ролей, которые человек может выполнять, но три, которые вы раскрыли, достаточно хороши, чтобы обсудить сценарий, раскрывающий несколько важных последствий .

3 Но, как вы заметили, в будущем субъект может в конечном итоге предоставить URL - адреса « один ко многим» .

4 Определение интеграции для информационного моделирования ( IDEF1X ) - это очень рекомендуемый метод моделирования, который был установлен в качестве стандарта в декабре 1993 года Национальным институтом стандартов и технологий США (NIST). Он основан на (а) ранних теоретических работах, написанных единственным создателем реляционной модели данных, то есть доктором Е.Ф. Коддом; (б) взгляд на сущность-отношение , разработанный доктором П.П. Ченом ; а также о (c) методике проектирования логических баз данных, созданной Робертом Г. Брауном.

5 Стандарт IDEF1X определяет миграцию ключей как «процесс моделирования размещения первичного ключа родительского или универсального объекта [т.е. супертипа] в его дочернем объекте или объекте категории [т.е. подтипе] в качестве внешнего ключа».

6 В IDEF1X имя роли - это отличительная метка, назначенная атрибуту FK, чтобы выразить значение, которое оно содержит в области видимости соответствующего типа объекта.

7 За исключением, разумеется, гипотетических концептуальных свойств (и логических столбцов) Director.Etcetera и UserProfile.Etcetera , которые являются просто заполнителями, которые я использовал для предоставления возможности добавления дополнительных свойств (и столбцов), которые применяются к соответствующему типу концептуальной сущности. (и логическая таблица).

8 Например, добавление дополнительного столбца с атрибутом AUTO_INCREMENT к таблице базы данных, «работающей» на MySQL.

MDCCL
источник
2

Вы должны разделить это по таблицам следующим образом (показаны только столбцы, необходимые для представления концепции, но не обязательно все столбцы):

Users
ID   Username   FirstName   LastName   PasswordHash ...
 1   'Joe1'      'Joe'      'Smith'
 2   'Freddy'    'Fred'     'Jones'

Roles
ID   RoleType ....
 1   'Writer'
 2   'Director'
 3   'Actor'

User_Roles
User_ID   Role_ID ...
1         1
1         2
2         2
2         3

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

Вы можете видеть, что Joe1 является одновременно писателем и режиссером по записям в User_Roles. И Фредди и режиссер, и актер.

Это также позволяет вам добавлять больше ролей позже, не меняя систему. Просто вставьте записи для продюсера или редактора или чего-либо еще.

Таким образом, чтобы найти все имена пользователей актеров, у вас есть пара вариантов:

 Select Distinct Username
   from Users
  Where User_ID in (select User_ID from User_Roles where Role_ID = 3)

Или, если вы не знаете номер role_ID, тогда:

 Select Distinct Username
   from Users
  Where User_ID in (Select User_ID from User_Roles where Role_ID = 
                       (Select ID from Roles where RoleType = 'Actor')
                   )

Или вы также можете сделать это:

select u.Username, r.RoleType
  from Users u
 inner join User_Roles ur on ur.User_ID = u.ID
 inner join Roles r on r.ID = ur.Role_ID
 where r.RoleType = 'Actor'

(В этой версии вы также можете использовать, Where r.Role_ID = 3чтобы получить те же результаты.)

Но я бы использовал 1-й запрос и какой бы пункт WHERE я знал. В большой системе знание Role_ID, как правило, выполняется быстрее, чем текст, поскольку числовые данные «проще» и эффективнее для большинства механизмов SQL, для которых обрабатываются индексы.

Что касается контактных методов или фотографий или чего-то еще, я бы сделал их аналогичным образом:

Attributes
ID    MethodText    ...
1     'TwitterID'
2     'URL'
3     'CellPhone'
4     'Email'
5     'PictureLink'

Role_Attributes
Role_ID  Attribute_ID isRequired
3        5             1
3        4             1
3        3             0

User_Attributes
User_ID  Attribute_ID  AttributeData
1         4            'Joe@Example.com'
1         1            '@joe'
1         3            '555-555-5555'
1         5            'www.example.com/pics/myFace.png'

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

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

Это позволяет добавлять новые атрибуты с течением времени, без переписывания кода; просто обновите атрибуты и таблицы role_attributes, чтобы они соответствовали вашим новым правилам. Это также позволяет вам обмениваться атрибутами между ролями, без повторного ввода одних и тех же данных для каждого пользователя. Если для двух ролей требуются фотографии, им нужно загрузить только 1 фотографию, чтобы выполнить это требование.

СаМ
источник
Ага, я думаю, что это имеет смысл в одном отношении ... но мне не очень понятно, как, например, я бы перечислил всех действующих лиц вместе, скажем, с их именами пользователей (при условии, что данные об актерах хранятся в отдельная таблица).
веризм
Смотрите мои правки; Я добавил примеры запросов.
СаМ
Это очень полезно, спасибо. Я думаю, что, возможно, я не был полностью ясен в своем вопросе - извините. Я должен был прояснить, что таблицы для каждого типа (актер, директор и т. Д.) Будут иметь свой собственный уникальный набор атрибутов, относящихся только к этому типу пользователя. Например, у актера будет выстрел в голову (фотография), а у писателя - нет. Снова извиняюсь за то, что не буду более явным по этому поводу.
веризм
Контактные методы выглядят как отличное решение.
веризм
1
Изменено это на атрибуты, чтобы соответствовать требованиям к фотографиям и т. Д. Должно быть лучше, сейчас.
СаМ