Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Database schema for Books, Authors, Publishers and Users with bookshelves

I am unable to figure out an efficient way to establish relationships between tables. I want to have a database of books, authors, publishers and the users that sign-up and have their bookshelves (Read, Currently Reading, Want to Read (or Plan to Read)). I want the users to be able to select which books they've read, want to read or are currently reading.

P.s. I am aware of PK and FK in database table relations.

Edit: maybe this is a better way of doing it:

enter image description here

Then I shall use "Status" = (Read, Plant to Read and Currently reading) - please tell me if this is good and efficient!

like image 338
John Smith Avatar asked Jan 16 '14 10:01

John Smith


People also ask

What are the 3 types of schema in the database?

Schema is of three types: Logical Schema, Physical Schema and view Schema. Logical Schema – It describes the database designed at logical level. Physical Schema – It describes the database designed at physical level. View Schema – It defines the design of the database at the view level.

What is an example of a database schema?

For example, in the Oracle Database product, a schema represents only a part of a database: the tables and other objects are owned by a single user. Note: In SQL, a view is a virtual table that is based on the result-set of a statement. A view contains both rows and columns.

What is the relationship between a books and authors in DBMS?

What is the relationship between books and authors? An author can write several books and a book can have more than one author, so this is an example of a many-to-many relationship. A many-to-many relationship can only be represented by creating a new table in the database.

What is the relationship between publisher and book dimension table?

books table stores book data including title, total pages, rating, ISBN, and published date. publishers table stores publisher names. authors table stores books' authors. book_authors table stores the relationship between books and authors.


1 Answers

You'll need a N:M link between books and authors, since a book might have multiple authors and each author might have written more than one book. In a RDBMS that means you'll need a written_by table.

The link between books and publishers however is different. Any given book can only have one publisher (unless in your system different editions of a book are considered the same book). So all you need here is a publisher_id foreign key in books

Lastly, and most importantly you're looking at the readers / users. And their relation to books. Naturally, this is also a N:M relation. I sure hope that people read more than one book (we all know what happens if you only ever read one...) and surely a book is read by more than one person. That calls for a book_users connection table. The real question here is, how to design it. There are three basic designs.

  1. Separate tables by type of relation. (as outlined by @just_somebody ) Advantages: You only have INSERTS and DELETES, never UPDATES. While this looks kind of neat, and somewhat helps with query optimization, most of the time it serves no actual purpose other than showing off a big database chart.

  2. One table with a status indicator. (as outlined by @Hardcoded) Advantages: You only have one table. Disadvantages: You'll have INSERTS, UPDATES and DELETES - something RDBMS can easily handle, but which has its flaws for various reasons (more on that later) Also, a single status field implies that one reader can have only one connection to the book at any time, meaning he could only be in the plan_to_read, is_reading or has_read status at any point in time, and it assumes an order in time this happens. If that person would ever plan to read it again, or pause, then reread from the begining etc, such a simple series of status indicators can easily fail, because all of a sudden that person is_reading now, but also has_read the thing. For most applications this still is a reasonable approach, and there are usually ways to design status fields so they are mutually exclusive.

  3. A log. You INSERT every status as a new row in a table - the same combination of book and reader will appear more than once. You INSERT the first row with plan_to_read, and a timestamp. Another one with is_reading. Then another one with has_read. Advantages: You will only ever have to INSERT rows, and you get a neat chronology of things that happened. Disadvantages: Cross table joins now have to deal with a lot more data (and be more complex) than in the simpler approaches above.

You may ask yourself, why is there the emphasis on whether you INSERT, UPDATE or DELETE in what scenario? In short, whenever you run an UPDATE or DELETE statement you are very likely to in fact lose data. At that point you need to stop in your design process and think "What is it I am losing here?" In this case, you lose the chronologic order of events. If what users are doing with their books is the center of your application, you might very well want to gather as much data as you can. Even if it doesn't matter right now, that is the type of data which might allow you to do "magic" later on. You could find out how fast somebody is reading, how many attempts they need to finish a book, etc. All that without asking the user for any extra input.

So, my final answer is actually a question:

Would it be helpful to tell someone how many books they read last year?

Edit

Since it might not be clear what a log would look like, and how it would function, here's an example of such a table:

CREATE TABLE users_reading_log (
  user_id INT,
  book_id INT,
  status ENUM('plans_to_read', 'is_reading', 'has_read'),
  ts TIMESTAMP DEFAULT NOW()
)

Now, instead of updating the "user_read" table in your designed schema whenever the status of a book changes you now INSERT that same data in the log which now fills with a chronology of information:

INSERT INTO users_reading_log SET 
  user_id=1,
  book_id=1,
  status='plans_to_read';

When that person actually starts reading, you do another insert:

INSERT INTO users_reading_log SET 
  user_id=1,
  book_id=1,
  status='is_reading';

and so on. Now you have a database of "events" and since the timestamp column automatically fills itself, you can now tell what happened when. Please note that this system does not ensure that only one 'is_reading' for a specific user-book pair exists. Somebody might stop reading and later continue. Your joins will have to account for that.

like image 175
Hazzit Avatar answered Oct 06 '22 00:10

Hazzit