Разработка группы с типами и элементами с типами, где тип элемента относится к типу группы - PullRequest
4 голосов
/ 20 марта 2020

У нас есть performers в нашей переводческой базе данных, и они работают удаленно. В настоящее время performers являются переводчиками и специалистами DTP, у них может быть много групп услуг, и у каждой группы услуг может быть много пунктов обслуживания. Когда они обращаются в нашу компанию, им нужно заполнить форму и выбрать услуги, которые они имеют. У каждой сервисной группы есть тип, например, перевод или DTP. Группе переводческих услуг нужны исходные и целевые языки, а группе сервисов DTP - нет. Проблема состоит в том, чтобы отобразить в списке выбора правильные сервисные позиции для сервисных групп.

enter image description here

На данный момент у меня есть следующий дизайн:

enter image description here

У меня есть performer_service_group_type и performer_service_item_type, что относится к performer_service_group_type для отображения правильного типа элемента службы для выбранного типа группы услуг в пользовательском интерфейсе. Но я не знаю, как это проверить с помощью ограничений целостности БД, потому что неправильное отношение типов элементов сервиса к типам групп обслуживания может быть сохранено без проблем. Вторая проблема - обнуляемые значения source_language_id и target_language_id для некоторых групп услуг (например, DTP)

Второй способ, который, я думаю, может быть представлен, состоит в том, чтобы иметь 2 отдельные таблицы для групповых услуг - performer_language_service_groups' and performer_misc_service_groups with 2 tables for each for service items and service items types. Here pros that misc service group wouldn't has source_language_id and target_language_id`, но минусами является необходимость создания 3 таблиц для каждой новой группы услуг, если у нас будет несколько (службы доставки и курьеры в пути).

Любой совет или предложение будет полезно , благодарность заранее.

Ответы [ 4 ]

1 голос
/ 27 марта 2020

Обнуляемость можно частично решить, создав 2 таблицы для SOURCE и TARGET языков (например, source_languages, target_languages. Там вы добавите по умолчанию значение с скажем ID = 1, VALUE = "DEFAULT", которое будет соответствовать вашему полю NULL в performer_service_groups, которое больше не должно быть обнуляемым (т. Е. Убрать нулевой флаг в performer_service_groups).

Таким образом, вы сохраните врожденное ограничение внешнего ключа SQL и на DML оно сработает, если вы измените source_language_id / target_language_id (соответственно) на performer_service_groups (то есть, если вы хотите NULL, вы будете принудительно добавьте ID = 1, чтобы удовлетворить ваш DML, в противном случае вы добавите соответствующий и при любом присоединении языка к performer_service_groups вы всегда получите возвращаемое значение, поэтому нет необходимости проверять наличие нулевого значения на стороне сервера, если вы do; для пользовательского интерфейса просто скрыть язык <select> или dropdown, если ID = 1 или VALUE = "DEFAULT").

О проверке ключа Я все еще думаю, я, вероятно, обновлю.

Подумал о проверке ключа. Что если вы создадите таблицу для своего 2-го уровня? Tes, это в основном будет отражать ваш пользовательский интерфейс. Для этого потребуется performer_service_groups, чтобы иметь другое поле идентификатора, state_id, которое будет указывать на вашу таблицу состояний. Это заставит вас включить это поле state_id в ваши запросы и, следовательно, отфильтровать ваш набор результатов по состояниям. По сути, это логическое разделение данных без физического разделения данных (просто путем добавления другого измерения; поскольку каждый идентификатор является новым измерением, можно pivot или group by получить таблицу xyz).

Если вы хотите go полностью строгое, теоретически вы можете проверить DML ваших пустых полей с помощью ПЕРЕД ТРИГГЕРАМИ или проверить проверки ограничений , но это добавит накладные расходы и неизбежно хрупкость и сложность . То же самое в теории может быть применено к проверке ключа, но я не знаю, в какой степени триггеры pg SQL могут гибко кодировать его (исходя из Oracle / PL SQL и MYSQL здесь).

Надеюсь, это имеет смысл.

1 голос
/ 29 марта 2020

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

<table name="Service Group" comment="for example, DTL">
  <column name="ID" pk="true" />
  <column name="Name" />
</table>

<table name="Service Group Type" comment="for example, Photoshop Markup">
  <column name="ID" pk="true" />
  <column name="Service Group" fk="[Service Group].[ID]" />
  <column name="Name" />
</table>

<table name="List Of Values" comment="for example, Language">
  <column name="ID" pk="true" />
  <column name="Name" />
</table>

<table name="Choice Of List Of Values" comment="for example, Japanese">
  <column name="ID" pk="true" />
  <column name="List Of Values" fk="[List Of Values].[ID]" />
  <column name="Description" />
</table>

<table name="Field" comment="for example, From Language">
  <column name="ID" pk="true" />
  <column name="Name" />
  <column name="List Of Values" fk="[List Of Values].[ID]" />
</table>

<table name="Service Group Field">
  <column name="Service Group" pk="true" fk="[Service Group].[ID]" />
  <column name="Field" pk="true" fk="[Field].[ID]" />
  <column name="Nullable" comment="N means optional, Y means mandatory" />
</table>

<table name="Service Record" comment="only retain core fields here, e.g. Performer, Currency, etc">
  <column name="ID" pk="true" />
  <column name="Service Group Type" fk="[Service Group Type].[ID]" />
  <column name="Performer" fk="[Performer].[ID]" />
  <column name="Currency" fk="[Currency].[ID]" />
  ...
</table>

<table name="Service Record Detail" comment="to organize all conditional fields">
  <column name="ID" pk="true" />
  <column name="Service Record" fk="[Service Record].[ID]" />
  <column name="Field" fk="[Field].[ID]" />
  <column name="Choice" fk="[Choice Of List Of Values].[ID]" />
  <column name="Free Text" />
</table>

Проблема 1 решается только сохранением типа службы в каждой записи службы. Вы все равно должны сделать проверку на экране логики c и предварительно сохранить лог c. Чтобы легко сгруппировать записи сервисов по группам сервисов, вы можете создать представления, которые присоединяют данные обратно к сервисной группе из типа сервисной группы. Проблема 2 решена с помощью списка необязательных / обязательных полей. Вы все равно должны добавить необходимые проверки: 1 - если указано значение, но шаблон не может быть найден из [Поле группы услуг], это избыточный ввод поля 2 - если значение не предоставлено, но из [Поле группы услуг] обязательно, пропущен ввод поля

1 голос
/ 24 марта 2020

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

Имейте в виду, что это логический дизайн , который не будет решите вашу проблему, как указано, но если вы «конвертируете» ее в PostgreSQL, она будет работать. Таким образом, вы можете экспериментировать с ограничениями и корректировать свой проект.

Note:
All attributes (columns) NOT NULL

PK = Primary Key
AK = Alternate Key   (Unique)
SK = Proper Superkey (Unique)
FK = Foreign Key

Пользовательский тип для типа услуги ID (дискриминатор); используйте этот тип для каждого SVC_TYP_ID столбца.

TYPE svc_typ ENUM (T, D)

Определите основы: услуги, типы услуг, языки, люди.

-- Service type identified by SVC_TYP_ID,
-- named SVC_TYP_NAME exists.
--
service_typ {SVC_TYP_ID::svc_typ, SVC_TYP_NAME}
         PK {SVC_TYP_ID}
         AK {SVC_TYP_ID}

(T, translation)
(D, dtp)


-- Service named SVC_NAME of type SVC_TYP_ID
-- is identified by SVC_ID.
--
 service_ {SVC_ID, SVC_TYP_ID, SVC_NAME}
      PK {SVC_ID}
      AK {SVC_NAME}
      SK {SVC_ID, SVC_TYP_ID}
      FK {SVC_TYP_ID} REFERENCES service_typ

(WTR, T, written translation)
(EDT, T, editing)
(PRF, T, proof reading)
(IND, D, in-design markup)
(PHT, D, photoshop markup)
(ACD, D, autocad markup)


-- Language name LANG_NAME,
-- identified by LANG_ID exists.
--
lang {LANG_ID, LANG_NAME}
  PK {LANG_ID}
  AK {LANG_NAME}

(EN, English)
(FR, French)
(RU, Russian)


-- Perfomer (person) identified by PERF_ID
-- named FNAME, LNAME exists.
--
perfomer {PERF_ID, FNAME, LNAME}
      PK {PERF_ID}

(1, Lev,  Tolstoy)
(2, Jim,  Blah)
(3, Joe,  Doe)
(4, Jane, Doe)

Люди предоставляют услуги, каждый человек может предоставить более одного вида услуг . В этом примере общим термином для лица, предоставляющего услугу, является «исполнитель». Translator и dtp-professional - это подтипов исполнителя супертип , дескриптор тип сервиса . Один и тот же исполнитель может предоставить несколько типов услуг.

-- Perfomer PERF_ID registered for service type SVC_TYP_ID.
--
perf_svc_typ {PERF_ID, SVC_TYP_ID, cols_common_to_all}
          PK {PERF_ID, SVC_TYP_ID}
         FK1 {PERF_ID}    REFERENCES perfomer
         FK2 {SVC_TYP_ID} REFERENCES service_typ

(1, T, ... )
(2, T, ... )
(3, D, ... )
(4, T, ... )
(4, D, ... ) -- PERF_ID = 4 does translations and dtp


-- Performer PERF_ID is registered as a translator.
--
-- note: (SVC_TYP_ID = T)
--
translator {PERF_ID, SVC_TYP_ID, cols_specific_to_translators}
        PK {PERF_ID}
     CHECK (SVC_TYP_ID = T::svc_typ)

        FK {PERF_ID, SVC_TYP_ID} REFERENCES perf_svc_typ

(1, T, ...)
(2, T, ...)
(4, T, ...)


-- Performer PERF_ID is registered as a DTP professional.
--
-- note: (SVC_TYP_ID = D)
--
dtp_prof {PERF_ID, SVC_TYP_ID, cols_specific_to_dtp_prof}
      PK {PERF_ID}
   CHECK (SVC_TYP_ID = D::svc_typ)

          FK {PERF_ID, SVC_TYP_ID} REFERENCES
perf_svc_typ {PERF_ID, SVC_TYP_ID}

(3, D, ...)
(4, D, ...)

Переводчик может предоставлять услуги на нескольких языках.

-- Performer PERF_ID, who registered as a translator,
-- speaks language LANG_ID.
--
perf_lang {PERF_ID, LANG_ID}
       PK {PERF_ID, LANG_ID}

      FK1 {PERF_ID} REFERENCES translator
      FK2 {LANG_ID} REFERENCES lang

(1, EN)
(1, FR)
(1, RU)
(2, EN)
(2, FR)
(4, FR)
(4, RU)

Каждый человек ( исполнитель) может предложить несколько групп услуг. Каждый сервис в группе должен быть одного типа сервиса. Исполнитель должен быть зарегистрирован в качестве поставщика этого типа услуг.

-- Performer PERF_ID offers a group of services,
-- identified by (PERF_ID, PERF_GROUP_NO);
-- each service in the group is of type SVC_TYP_ID.
--
svc_group {PERF_ID, PERF_GROUP_NO, SVC_TYP_ID}
       PK {PERF_ID, PERF_GROUP_NO}
       SK {PERF_ID, PERF_GROUP_NO, SVC_TYP_ID}
       FK {PERF_ID, SVC_TYP_ID} REFERENCES perf_svc_typ

(1, 1, T)
(1, 2, T)
(2, 1, T)
(3, 1, D)
(4, 1, T)
(4, 2, D)

Каждая группа услуг каждого исполнителя перечисляет услуги, относящиеся к типу услуги этой группы, предлагаемые этим исполнителем.

-- Performer PERF_ID offers translation (SVC_TYP_ID = T)
-- service SVC_ID from FROM_LANG to TO_LANG,
-- in that performer's service group
-- identified by (PERF_ID, PERF_GROUP_NO)
--
trans_svc {
         PERF_ID
       , PERF_GROUP_NO
       , SVC_ID
       , SVC_TYP_ID
       , FROM_LANG
       , TO_LANG
       }

PK {PERF_ID, PERF_GROUP_NO, SVC_ID, FROM_LANG, TO_LANG}

CHECK (SVC_TYP_ID = T::svc_typ)

FK1 {PERF_ID, PERF_GROUP_NO, SVC_TYP_ID} REFERENCES svc_group
FK2 {SVC_ID, SVC_TYP_ID} REFERENCES service_
FK3 {PERF_ID} REFERENCES  translator

      FK4 {PERF_ID, FROM_LANG} REFERENCES
perf_lang {PERF_ID, LANG_ID}

      FK5 {PERF_ID, TO_LANG} REFERENCES
perf_lang {PERF_ID, LANG_ID}


(1, 1, WTR, T, EN, RU) -- for translation from <> to
(1, 1, WTR, T, FR, RU)
(1, 2, PRF, T, RU, RU) -- for edit and proof from = to
(1, 2, EDT, T, RU, RU)
(1, 2, PRF, T, EN, EN)
(2, 1, WTR, T, EN, FR)
(2, 1, WTR, T, FR, EN)
(2, 1, EDT, T, EN, EN)
(2, 1, PRF, T, EN, EN)
(2, 1, PRF, T, FR, FR)
(4, 1, WTR, T, FR, RU)
(4, 1, PRF, T, FR, FR)
-- Performer PERF_ID offers DTP (SVC_TYP_ID = D) service_ SVC_ID
-- in group identified by (PERF_ID, PERF_GROUP_NO).
--
dtp_svc {PERF_ID, PERF_GROUP_NO, SVC_ID, SVC_TYP_ID}
     PK {PERF_ID, PERF_GROUP_NO, SVC_ID}

  CHECK (SVC_TYP_ID = D::svc_typ)

    FK1 {PERF_ID, PERF_GROUP_NO, SVC_TYP_ID} REFERENCES svc_group 

    FK2 {SVC_ID, SVC_TYP_ID} REFERENCES service_ 

    FK3 {PERF_ID} REFERENCES  dtp_prof

(3, 1, PHT, D)
(3, 1, ACD, D)
(4, 2, IND, D)
(4, 2, ACD, D)
0 голосов
/ 02 апреля 2020

Сейчас я буду придерживаться следующего решения.

enter image description here

Если у меня будет новая группа со специальными полями для конкретной группы услуг, я бы сделал новый таблицу с отношением 1-1 и добавьте логическое поле к service_group в качестве флага для необходимости извлечения чего-либо. Возможно позже я сделаю go для более динамичной c вещи. Если у кого-то еще есть идеи, как улучшить эту схему - хотелось бы знать:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...