Banco de dados de questões de design com relacionamentos
-
03-07-2019 - |
Pergunta
Eu estou trabalhando em uma atualização para um banco de dados existente que foi projetado sem qualquer do código para implementar o projeto a ser considerada. Agora eu bater em uma parede de tijolos em termos de implementação do projeto de banco de dados no código. Estou certo se o seu problema um com o design do banco de dados ou se eu simplesmente não estou vendo a solução correta sobre como o que precisa ser feito.
A lógica básica estipula o seguinte:
- Os usuários acessam os treinamentos on-line por meio de assentos. Os usuários podem ter vários lugares.
- Os assentos são adquiridos por empresas e ter um relacionamento muitos-para-muitos com os produtos.
- Um produto tem um relacionamento muitos-para-muitos com os módulos.
- Um módulo tem um relacionamento muitos-para-muitos com lições.
- As lições são o acesso aos usuários finais para a sua formação.
- Para turvar as águas, por uma razão ou outra, alguns usuários têm vários lugares que contêm os mesmos produtos.
- Certificação ocorre em um por produto base, não em uma base por Seat.
- Os usuários têm um relacionamento muitos-para-muitos com lições que armazena seu status atual ou marcar para a lição.
- Os usuários certificar de um Produto quando completar todas as lições em todos os módulos do produto.
- Também é importante saber quando todas as lições para um módulo específico são completadas por um usuário.
- Alguns assentos será para recertificação o que significa que usuários que previamente certificados para um produto pode se inscrever e fazer um exame de recertificação.
- Devido o artigo 11, os usuários podem e terá vários registros de certificação.
- Editar: Quando um usuário conclui uma lição (pontuação melhor do que 80%), em seguida, o usuário tem (de acordo com a lógica de negócios atual) completou a lição para todos os produtos e todos os lugares que contêm a lição.
O problema que eu continuo correndo para com o design atual e a lógica de negócios como eu tenho mais ou menos descrito é que eu não consigo encontrar uma maneira de amarrar efetivamente se um usuário certificado para um determinado produto e assento vs quando eles não têm. Eu mantenho-me bater senões tentando estabelecer quais os produtos em que assentos foram certificadas para o utilizador e que não têm. Parte do problema é porque se eles estão atualmente registrados para múltiplas do mesmo produto em diferentes lugares, então eu tenho que contar o produto apenas uma vez.
Abaixo está uma cópia da parte do esquema que está envolvido. Todas as sugestões sobre como melhorar o design ou desenhar a associação em código seria apreciada. No caso é importante, este site é construído sobre a pilha LAMPP.
Você pode ver a parte relevante do esquema de banco de dados aqui: http://lpsoftware.com/problem_db_structure.png
Solução
O que você está procurando relacional divisão Não implementado diretamente no SQL, mas isso pode ser feito. Pesquisa do Google para outros exemplos.
Outras dicas
Depois de um rápido olhar para o esquema Eu acho que uma das coisas que você pode fazer é criar um 'to_be_certified' mesa. Preenchê-lo com user_id, product_id e SEAT_ID quando um produto é atribuído a um assento (quando product_seat_rtab é preenchida).
Ao adicionar um registro à tabela certification_rtab, excluir o registro correspondente na tabela 'to_be_certified'. Isto lhe dará um fácil acesso a todos os produtos que são certificados por usuários e os que não são.
Para se livrar de product_ids duplicados, você pode agrupar por product_id.
Você precisa fazer alterações na tabela de 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)
);
Em seguida, você pode consultar para cada produto que um usuário tem um assento para, ele está certificado? Isso pressupõe que o número de lições que ele marcou, digamos, 50% ou mais é o mesmo que o número de aulas em todos os módulos do produto.
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;
UPDATE:
Eu considerar esta questão e ter examinado se ele permitiria que as coisas funcionem melhor do que simplesmente remover a mesa de user_seat_rtab e, em seguida, use a tabela certification_rtab equivalente (provavelmente renomeado) para manter todas as informações sobre o status de sede de um usuário . Desta forma, existe uma relação direta estabelecida entre um usuário, o seu lugar, cada produto dentro do assento, e se o usuário tem certificado pelo Produto e lugar específico.
Assim, gostaria de aplicar as seguintes alterações ao esquema postado com a pergunta:
DROP TABLE user_seat_rtab;
RENAME TABLE certification_rtab TO something_different;
Uma alternativa para mais normalizar essa nova estrutura seria fazer algo como isto:
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;
Eu realmente não estou certo se isso iria resolver o problema ou se ele vai apenas mudar a natureza do problema um pouco e cria novos. Então, alguém tem alguma outras críticas ou sugestões?