Проблемы проектирования баз данных с отношениями - PullRequest
1 голос
/ 02 октября 2008

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

Основная логика предусматривает следующее:

  1. Пользователи получают доступ к онлайн-тренингам через места. Пользователи могут иметь несколько мест.
  2. Места приобретаются компаниями и имеют много-много отношений с продуктами.
  3. Продукт имеет отношение многих ко многим с модулями.
  4. Модуль имеет много-много-много отношений с Уроками.
  5. Уроки - доступ конечных пользователей к обучению.
  6. Чтобы затопить воду, по тем или иным причинам у некоторых пользователей есть несколько мест, в которых находятся одни и те же продукты.
  7. Сертификация проводится для каждого продукта, а не для каждого рабочего места.
  8. Пользователи имеют отношение «многие ко многим» с уроками, в которых хранится их текущий статус или оценка за урок.
  9. Пользователи сертифицируют для Продукта, когда они заканчивают все Уроки во всех Модулях для Продукта.
  10. Также важно знать, когда все уроки для конкретного модуля выполнены пользователем.
  11. Некоторые места предназначены для повторной сертификации. Это означает, что пользователи, ранее сертифицированные для продукта, могут зарегистрироваться и сдать повторный сертификационный экзамен.
  12. В соответствии с правилом 11 пользователи могут иметь и будут иметь несколько сертификационных записей.
  13. Редактировать: Когда Пользователь заканчивает Урок (баллы лучше, чем 80%), тогда Пользователь (в соответствии с текущей бизнес-логикой) завершил Урок для всех Продуктов и всех Мест, которые содержат Урок.

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

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

Вы можете просмотреть соответствующую часть схемы базы данных здесь: http://lpsoftware.com/problem_db_structure.png

Ответы [ 4 ]

2 голосов
/ 02 октября 2008

То, что вы ищете, это реляционное деление Не реализовано непосредственно в SQL, но это может быть сделано. Ищите в Google другие примеры.

0 голосов
/ 03 октября 2008

UPDATE:

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

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

DROP TABLE user_seat_rtab;
RENAME TABLE certification_rtab TO something_different;

Альтернативой дальнейшей нормализации этой новой структуры было бы сделать что-то вроде этого:

ALTER TABLE user_seat_rtab 
    DROP PRIMARY KEY;
    ADD COLUMN product_id int(10) unsigned NOT NULL;
    ADD CONSTRAINT pk_user_seat_product PRIMARY KEY (user_id, seat_id, product_id);
    ADD CONSTRAINT fk_product_user_seat FOREIGN KEY (product_id) REFERENCES product_rtab(id) ON DELETE RESTRICT;

Я не совсем уверен, решит ли это проблему или просто немного изменит природу проблемы при введении новых. Итак, есть ли у кого-нибудь другая критика или предложения?

0 голосов
/ 02 октября 2008

Вам необходимо внести изменения в таблицу lessonstatus_rtab:

CREATE TABLE lessonstatus_rtab (
  user_id    INT NOT NULL,
  seat_id    INT NOT NULL,
  lesson_id  INT NOT NULL REFERENCES lesson_rtab,
  accessdate TIMESTAMP,
  score      NUMERIC(5,2) NOT NULL DEFAULT 0,
  PRIMARY KEY (user_id, seat_id, lesson_id),
  FOREIGN KEY (user_id, seat_id) REFERENCES user_seat_rtab (user_id, seat_id)
);

Тогда вы можете запросить каждый продукт, на который у пользователя есть место, он сертифицирован? Это предполагает, что количество уроков, которые он набрал, скажем, 50% или выше, совпадает с количеством уроков во всех модулях продукта.

SELECT p.name, us.user_id, us.seat_id, COUNT(l.id) = COUNT(lu.lesson_id) AS is_certified
FROM user_seat_rtab AS us
 JOIN seat_rtab AS s ON (s.id = us.seat_id)
 JOIN product_seat_rtab AS ps ON (ps.seat_id = s.id)
 JOIN product_rtab AS p ON (p.id = ps.product_id)
 JOIN product_module_rtab AS pm ON (pm.product_id = p.id)
 JOIN module_rtab AS m ON (m.id = pm.module_id)
 JOIN module_lesson_rtab AS ml ON (ml.module_id = m.id)
 JOIN lesson_rtab AS l ON (l.id = ml.lesson_id)
 LEFT OUTER JOIN lessonstatus_rtab AS lu 
   ON (lu.lesson_id = l.id AND lu.user_id = us.user_id 
     AND lu.seat_id = us.seat_id AND lu.score > 0.50)
GROUP BY p.id, us.user_id, us.seat_id;
0 голосов
/ 02 октября 2008

После быстрого взгляда на схему я думаю, что одна из вещей, которые вы можете сделать, - создать таблицу to_be_certified. Заполните его user_id, product_id и seat_id, когда продукт назначен на место (когда заполнен product_seat_rtab).

При добавлении записи в таблицуtification_rtab удалите соответствующую запись в таблице to_be_certified. Это даст вам легкий доступ ко всем продуктам, которые сертифицированы для пользователей, и к тем, которые не сертифицированы.

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

...