This is for a library management system.
I have two tables, one is Books with fields BookId, Title, AuthorId, PublisherId, ISBN, ISBN13, PublishedOn, NumberOfPages, etc etc.
Other is BookTransactions that contains all the transaction of books that are issued to, or received from any student, with fields TransactionId, BookId, IssuedOn, IssuedTo, ReceviedOn, etc. etc.
Now the problem is, let’s say I have this book The God Delusion, and there are 200 copies of it. The entry in Books table would be like this
7 The God Delusion 21 32 0618680004 978-0618680009 .....
8 The God Delusion 21 32 0618680004 978-0618680009 .....
9 The God Delusion 21 32 0618680004 978-0618680009 .....
10 The God Delusion 21 32 0618680004 978-0618680009 .....
.
.
.
(200 rows). Everything else is exactly the same, just there are 200 entries for each book, now I know I can have a column named Quantity, but hear this (and that’s why the question)
The table BookTransactions might look a like this after a while
1 9 4/3/2012 ABC __
2 10 4/3/2012 PQR __
3 7 4/3/2012 XYZ 7/3/2012
Thus clearly indicating the 3 ‘The God Delusion’ book were issued on same day. The benefit is that I can check that if book number 7 is issued or not, if not then I can issue it, something like this
sqlCommand.CommandText = "SELECT Count(*) FROM BookTransactions WHERE BookId=7 AND ReceivedOn is NULL";
// if a book is received, its in library and can be issued again
if (Int32.Parse(sqlCommand.ExecuteScalar().ToString()) == 0)
bookInstance.IssueThisBook();
else
MessageBox.Show("This book is already issued to someone, please select a different book");
Now the problem with having a column quantity is that say if Books table looked like this
7 The God Delusion 21 32 0618680004 978-0618680009 ..... 200
// the last one indicates quantity
The entry in BookTransaction now will look like this
1 7 4/3/2012 ABC __
and now if run this code,
sqlCommand.CommandText = "SELECT Count(*) FROM BookTransactions WHERE BookId=7 AND ReceivedOn is NULL";
// if a book is received, its in library and can be issued again
if (Int32.Parse(sqlCommand.ExecuteScalar().ToString()) == 0)
bookInstance.IssueThisBook();
else
MessageBox.Show("This book is already issued to someone, please select a different book");
It will show that the book is issued to someone, even though only one copy is issued and there are still 199 copies remaining in the library.
I know there are many ways to overcome this, one way that I can think of is to do something like this
sqlCommand.CommandText = "SELECT Count(*) FROM BookTransactions WHERE BookId=7 AND ReceivedOn is NULL";
sqlCommandOther.CommandText = "SELECT Quantity FROM Books WHERE Bookid=7"
// if the count is not equal to total quantity then there are some books availabe in libray
if (Int32.Parse(sqlCommand.ExecuteScalar().ToString()) != Int32.Parse(sqlCommandOther.ExecuteScalar().ToString()))
bookInstance.IssueThisBook();
else
// all books are currently issued
MessageBox.Show("All copies of this book are already issued, please select a different book");
Well, this is the only way I could think of, but I know this is not efficient, I want to know is there another way I can remove this redundancy of having 200 rows in books just because there are 200 copies? (and I mean any other way except what I described in previous paragraph.) What would be the best way to achieve what I am trying to do.
I hope I made myself clear.
Edit StarPilot’s point is worth noticing. Do I really need 200 different rows/records? Because just like he pointed out, how will I track if a particular book, say #50 is lost or damaged? Taking this into part it does looks like there must be redundancy, right?
Try structuring your database like the following.
The
BookStocktable would hold one row for every book, and theBookCheckOuttable will hold a new row every time a check out occurs. So, it’s trival to find out how many are in stock with the following query.Furthermore, it’s very trival to get all of the
actualchecked out books with this query.And finally, you’ve removed the duplication of the book, it’s only in the database once. Generally speaking, when working with inventory, you need to track all transactions and not just a quantity. It may feel a little over-designed to you but the
BookStocktable can easily be used later to place in who stocked it, or even furthermore use bar code scanning to stock books by scanning the ISBN number. Imagine scanning the ISBN number, lookup the book on that, and just adding a row to theBookStocktable and BOOM you’ve added stock!Oh, and finally you could use bar code scanning to check in really easily because the
BookCheckOutcan easily navigate to and from theBook.