Проблемы с проектированием базы данных, связанные со связями
-
03-07-2019 - |
Вопрос
Я работаю над обновлением существующей базы данных, которая была разработана без какого-либо кода для реализации рассматриваемого проекта.Теперь я уперся в кирпичную стену с точки зрения реализации дизайна базы данных в коде.Я уверен, что это проблема с дизайном базы данных или я просто не вижу правильного решения о том, как то, что нужно сделать.
Основная логика предусматривает следующее:
- Пользователи получают доступ к онлайн-тренингам через Места.Пользователи могут занимать несколько мест.
- Места приобретаются компаниями и имеют отношение "многие ко многим" к Продуктам.
- Продукт имеет отношение "многие ко многим" с Модулями.
- Модуль имеет отношение "многие ко многим" к Урокам.
- Уроки - это доступ конечных пользователей к своему обучению.
- Чтобы замутить ситуацию, по той или иной причине у некоторых Пользователей есть несколько Мест с одними и теми же Продуктами.
- Сертификация проводится для каждого Продукта, а не для каждого Места.
- Пользователи имеют отношение "многие ко многим" к урокам, в котором хранится их текущий статус или оценка за урок.
- Пользователи сертифицируют Продукт, когда они завершают все Уроки во всех Модулях для Продукта.
- Также важно знать, когда Пользователь завершил все Уроки по определенному Модулю.
- Некоторые места будут предназначены для повторной сертификации, что означает, что Пользователи, ранее прошедшие сертификацию на Продукт, могут зарегистрироваться и сдать экзамен на повторную сертификацию.
- В соответствии с правилом 11 пользователи могут иметь и будут иметь несколько записей сертификации.
- Редактировать:Когда Пользователь завершает Урок (оценка превышает 80%), это означает, что Пользователь (в соответствии с текущей бизнес-логикой) завершил Урок для всех Продуктов и всех Мест, содержащих Урок.
Проблема, с которой я продолжаю сталкиваться при текущем дизайне и бизнес-логике, как я их более или менее описал, заключается в том, что я не могу найти способ эффективно связать, сертифицирован ли пользователь для конкретного продукта и места, с тем, когда у него их нет.Я продолжаю натыкаться на препятствия, пытаясь установить, какие Продукты под какими Сиденьями сертифицированы для Пользователя, а какие нет.Частично проблема заключается в том, что если в данный момент они зарегистрированы для нескольких товаров одного и того же вида под разными сиденьями, то мне приходится подсчитывать Товар только один раз.
Ниже приведена копия той части схемы, которая задействована.Будем признательны за любые предложения о том, как улучшить дизайн или нарисовать ассоциацию в коде.На случай, если это имеет значение, этот сайт построен на стеке LAMPP.
Вы можете просмотреть соответствующую часть схемы базы данных здесь: http://lpsoftware.com/problem_db_structure.png
Решение
Вам нужно реляционное разделение Не реализовано непосредственно в SQL, но это может быть сделано. Найдите в Google другие примеры.
Другие советы
После быстрого взгляда на схему я думаю, что одна из вещей, которые вы можете сделать, - это создать таблицу to_be_certified. Заполните его user_id, product_id и seat_id, когда продукт назначен на место (когда заполнен product_seat_rtab).
При добавлении записи в таблицуtification_rtab удалите соответствующую запись в таблице to_be_certified. Это даст вам легкий доступ ко всем продуктам, которые сертифицированы для пользователей, и к тем, которые не сертифицированы.
Чтобы избавиться от дубликатов product_id, вы можете группировать по product_id.
Вам нужно внести изменения в таблицу 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;
Обновить:
Я дополнительно рассмотрел этот вопрос и рассмотрел, позволит ли это работать лучше, если просто удалить таблицу user_seat_rtab, а затем использовать эквивалентную таблицу certification_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;
Я не совсем уверен, решит ли это проблему или это просто немного изменит характер проблемы, вводя новые.Итак, есть ли у кого-нибудь еще какие-либо критические замечания или предложения?