2

这是一个图书馆管理系统。

我有两张表,一张是Books带字段的BookId, Title, AuthorId, PublisherId, ISBN, ISBN13, PublishedOn, NumberOfPages, etc etc.

其他是BookTransactions包含向任何学生发行或从任何学生接收的书籍的所有交易,具有字段TransactionId, BookId, IssuedOn, IssuedTo, ReceviedOn, etc. etc.

现在的问题是,假设我有这本书The God Delusion,并且有 200 份。表中的条目Books将是这样的

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 行)。其他一切都完全相同,只是每本书有 200 个条目,现在我知道我可以有一个名为 的列Quantity,但是听到这个(这就是问题的原因)

一段时间后,表格BookTransactions可能看起来像这样

1   9    4/3/2012   ABC   __  
2   10   4/3/2012   PQR   __  
3   7    4/3/2012   XYZ   7/3/2012

从而清楚地表明3本《神幻》书是在同一天发行的。好处是我可以检查是否发行了第 7 本书,如果没有,那么我可以发行它,像这样

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");

现在有一个列数量的问题是说如果Books表看起来像这样

7  The God Delusion  21  32  0618680004  978-0618680009 ..... 200 
// the last one indicates quantity

现在的条目BookTransaction将如下所示

1   7    4/3/2012   ABC   __

现在如果运行这段代码,

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");

它会显示这本书是发给某人的,即使只发行了一本,图书馆里还剩下 199 份。

我知道有很多方法可以克服这个问题,我能想到的一种方法是做这样的事情

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");

好吧,这是我能想到的唯一方法,但我知道这效率不高,我想知道是否有另一种方法可以消除仅因为有 200 个副本而在书中有 200 行的冗余?(我的意思是除了我在上一段中描述的任何其他方式。)实现我想要做的事情的最佳方式是什么。
我希望我说清楚了。

编辑StarPilot 的观点值得注意。我真的需要 200 条不同的行/记录吗?因为就像他指出的那样,如果某本书(例如 #50)丢失或损坏,我将如何追踪?考虑到这一点,它看起来确实必须有冗余,对吧?

4

5 回答 5

4

您必须区分书籍(标题)和副本。这意味着你应该有

  1. 书籍表格,其中将包含有关书籍的信息,每本书只有一行;

  2. 副本表,每本书包含与您拥有的副本一样多的行(最好带有一些序列号,允许您将一个副本与另一个副本区分开来),将 BookId 作为外键

  3. 具有 CopyId 作为外键的事务的表。

于 2012-07-31T17:50:04.193 回答
1

这在很大程度上取决于您需要如何处理这些数据。

如果您只关心是否有任何给定标题的书籍要发行,您可以完全按照您所做的那样使用数量字段,Books因为您可以在每次发行书籍时减少并在每次返回时增加。要知道是否还有剩余的副本,您只需要知道计数器是否大于零。如果您还需要跟踪当前发行的书籍数量,您也可以在Books表中保留原始数量,并使用它与当前数量进行比较。

如果您认为您将需要跟踪一本书的每个单独副本,您仍然可以通过将一本书的所有不变数据保留在Books表中并使用BookInstance表(或类似的东西)来保留大量冗余跟踪各个实例。这样,您仍然可以将发行交易链接到书籍的各个实例,但不会携带原始设计中包含的所有冗余数据。

于 2012-07-31T17:51:23.680 回答
1

尝试像下面这样构建您的数据库。

Book { BookId, Title, AuthorId, PublisherId, ISBN, ISBN13, PublishedOn, NumberOfPages, etc }
BookStock { BookStockId, BookId, StockDateTime }
BookCheckOut { BookCheckOutId, BookStockId, CheckOutDate, CheckInDate, Quantity }

BookStock表将为每本书保留一行,并且BookCheckOut每次结帐时该表将保留一个新行。因此,通过以下查询找出有多少库存是微不足道的。

SELECT COUNT(bs.BookStockId) - (SELECT COUNT(bco.BookCheckOutId) FROM BookCheckOut bco WHERE bco.BookStockId = bs.BookStockId AND bco.CheckInDate IS NULL) FROM BookStock bs

此外,使用此查询获取所有已actual签出的书籍非常简单。

SELECT * FROM BookCheckOut WHERE BookStockId = {id} AND CheckInDate IS NULL

最后,你删除了这本书的重复,它只在数据库中一次。一般来说,在处理库存时,您需要跟踪所有交易,而不仅仅是数量。您可能会觉得有点过度设计,但该BookStock表可以很容易地用于以后放置它的存放者,或者甚至使用条形码扫描通过扫描 ISBN 号来存放书籍。想象一下扫描 ISBN 号,查找上面的书,然后在BookStock表格中添加一行,然后 BOOM 就添加了库存!

哦,最后您可以使用条码扫描非常轻松地办理登机手续,因为BookCheckOut可以轻松导航到Book.

于 2012-07-31T17:56:15.153 回答
0

您需要另一张桌子 - 称之为 BookMaster。它将包括一个 id 以及关于这本书的所有常见数据,例如标题、作者等。您当前的 Books 表将有一个 BookMasterId 列来连接这两个表。然后,您将拥有“The God Delusion”的单个 BookMaster 记录,并且您仍将拥有 200 个 Book 记录,因此您可以跟踪每个单独的副本。

于 2012-07-31T17:50:26.793 回答
0

我建议使用一个新表“BookCopies”来跟踪不同的副本。CopyNumber、BookID(双主键)和状态“可用、丢失等”之类的东西

然后,您可以查询您的副本表以获取可用状态,而不是随着时间的推移可能会非常大的事务表。

于 2012-07-31T17:59:51.990 回答