Você precisará de um link N:M entre
books
e authors
, pois um livro pode ter vários autores e cada autor pode ter escrito mais de um livro. Em um RDBMS, isso significa que você precisará de um written_by
tabela. O link entre
books
e publishers
porém é diferente. Qualquer livro pode ter apenas uma editora (a menos que em seu sistema diferentes edições de um livro sejam consideradas o mesmo livro). Então tudo que você precisa aqui é um publisher_id
chave estrangeira em books
Por último, e mais importante, você está olhando para os leitores/usuários. E sua relação com os livros. Naturalmente, esta também é uma relação N:M. Espero que as pessoas leiam mais de um livro (todos sabemos o que acontece se você ler apenas um...) e certamente um livro é lido por mais de uma pessoa. Isso exige um
book_users
tabela de conexão. A verdadeira questão aqui é, como projetá-lo. Existem três desenhos básicos. -
Tabelas separadas por tipo de relação . (conforme descrito por @just_somebody ) Vantagens:Você só tem INSERTS e DELETES, nunca UPDATES. Embora isso pareça legal e ajude um pouco na otimização de consultas, na maioria das vezes não serve a nenhum propósito real além de exibir um grande gráfico de banco de dados.
-
Uma tabela com umstatus
indicador . (conforme descrito por @Hardcoded) Vantagens:Você só tem uma mesa. Desvantagens:Você terá INSERTS, UPDATES e DELETES - algo que o RDBMS pode manipular facilmente, mas que tem suas falhas por vários motivos (mais sobre isso depois) Além disso, um únicostatus
O campo implica que um leitor pode ter apenas uma conexão com o livro a qualquer momento, o que significa que ele só pode estar noplan_to_read
,is_reading
ouhas_read
status a qualquer momento, e assume uma ordem no tempo em que isso acontece. Se essa pessoa planejasse lê-lo novamente , ou pausar e reler desde o início, etc., uma série tão simples de indicadores de status pode falhar facilmente, porque de repente essa pessoais_reading
agora, mas tambémhas_read
a coisa. Para a maioria dos aplicativos, essa ainda é uma abordagem razoável e geralmente há maneiras de projetar campos de status para que sejam mutuamente exclusivos.
-
Um registro . Você INSERT cada status como uma nova linha em uma tabela - a mesma combinação de livro e leitor aparecerá mais de uma vez. Você INSERIR a primeira linha complan_to_read
, e um carimbo de data/hora. Outro comis_reading
. Em seguida, outro comhas_read
. Vantagens:Você só precisará inserir linhas e obterá uma cronologia organizada das coisas que aconteceram. Desvantagens:As junções entre tabelas agora precisam lidar com muito mais dados (e ser mais complexas) do que nas abordagens mais simples acima.
Você pode se perguntar, por que há ênfase em INSERT, UPDATE ou DELETE em qual cenário? Em resumo, sempre que você executar uma instrução UPDATE ou DELETE, é muito provável que você perde dados. Nesse ponto, você precisa parar em seu processo de design e pensar:"O que estou perdendo aqui?" Nesse caso, você perde a ordem cronológica dos eventos. Se o que os usuários estão fazendo com seus livros é o centro do seu aplicativo, você pode querer coletar o máximo de dados possível. Mesmo que não importe agora, esse é o tipo de dados que pode permitir que você faça "mágica" mais tarde. Você pode descobrir o quão rápido alguém está lendo, quantas tentativas eles precisam para terminar um livro, etc. Tudo isso sem pedir ao usuário qualquer entrada extra.
Então, minha resposta final é na verdade uma pergunta:
Editar
Como pode não estar claro como seria um log e como ele funcionaria, aqui está um exemplo de tal tabela:
CREATE TABLE users_reading_log (
user_id INT,
book_id INT,
status ENUM('plans_to_read', 'is_reading', 'has_read'),
ts TIMESTAMP DEFAULT NOW()
)
Agora, em vez de atualizar a tabela "user_read" em seu esquema projetado sempre que o status de um livro mudar, você agora INSIRA esses mesmos dados no log que agora preenche uma cronologia de informações:
INSERT INTO users_reading_log SET
user_id=1,
book_id=1,
status='plans_to_read';
Quando essa pessoa realmente começa a ler, você faz outra inserção:
INSERT INTO users_reading_log SET
user_id=1,
book_id=1,
status='is_reading';
e assim por diante. Agora você tem um banco de dados de "eventos" e como a coluna timestamp se enche automaticamente, agora você pode dizer o que aconteceu quando. Observe que este sistema não garante que exista apenas um 'is_reading' para um par de livro de usuário específico. Alguém pode parar de ler e depois continuar. Suas junções terão que levar em conta isso.