图书馆数据库设计外键

时间:2012-10-15 13:48:50

标签: mysql sql database-design

我正在为我的学校设计一个图书馆应用程序。我们有2-3个主要的库,有些部门有自己的库。我想知道这些查询是否正确?

Libraries 
ID Name
1  Walter
2  Wally
3  Maths dept library

Books
ID Book ID  BookName
1   1       Fundamentals of calculus
2   1       Mechanics 
3   2       Fundamentals of calculus
4   2       Biology

Lib_Book_LookUp
ID  libId bookId
1    1     1
2    1     2
3    2     1
4    2     2

我想解决的两个问题是:

  1. 查找特定图书的副本数量
  2. 找出哪些图书馆有特定图书
  3. 这就是我所拥有的:

    Select count(Book.bookId) where book.name = "Fundamentals of calculus";
    
    Select count(libId) from Lib_Book_lookUp, Book where Book.BookId = Lib_Book_lookUp.bookId groupBy(libId)
    

    我对这些问题的疑问:

    1. 是否有必要使用单独的查找表并将libId合并到Books表中并将其作为书表上的外键?
    2. 查询是否正确?

3 个答案:

答案 0 :(得分:4)

您的第一个查询缺少FROM子句。您也可以COUNT(*),但在这种情况下并不特别重要:

 SELECT count(Book.bookId) FROM Books WHERE BookName = "Fundamentals of calculus";

要找出哪些图书馆有特定图书,您不需要COUNT()汇总。相反,您需要加入WHERE子句。 COUNT()会告诉您有多少图书馆有图书,但哪些图书馆。为此,您需要一个返回Libraries.Name的查询。

SELECT
  /* Return library names */
  Libraries.Name
FROM 
  Libraries 
  /* Join through your lookup table to match a book name to a library name */
  JOIN Lib_Book_LookUp ON Libraries.ID = Lib_Book_LookUp.libId
  JOIN Books ON Books.ID = Lib_Book_LookUp.bookId
/* Which book to search for */
WHERE Books.BookName = 'Fundamentals of calculus'

查找表是合适的,因为它允许您将书籍规范化为Books表中的单个记录(如果它存在于多个库中)。如你所知,没有真正的理由在Books表中有多个副本,没有Book ID列的原因。事实上,Book ID列实际上是误导性的。有两种不同标题的书具有相同的标识1

Books表确实应该如下所示,每本书标题一个记录(假设标题为权威,忘记了真正的权威性事项,如ISBN)

Books
ID BookName
1  Fundamentals of calculus
2  Mechanics 
3  Biology

如果每个图书馆都有每本图书的多个副本,您可以考虑将每本图书的版本标准化为一个表格,以便通过图书馆条形码识别它们。然后,您将这些ID与库匹配为:

Books (defines bibliographic details)
ID BookName
1  Fundamentals of calculus
2  Mechanics 
3  Biology

Book_Copies (Matches Books.ID to barcode, barcode is Primary Key)
BookId Barcode
1      1234567
1      1234568
2      8654321
2      8654322

Lib_Book_LookUp (matches book copies to libraries, allowing multiple copies by barcode)
ID  libId bookBarcode
1    1     1234567
2    1     1234568
3    2     8654321
4    2     8654322

例如,要查询每个图书馆每本图书的份数,您可以使用:

SELECT 
  Libraries.Name,
  Books.BookName,
  COUNT(*)
FROM 
  Libraries
  JOIN Lib_Book_LookUp ON Libraries.ID = Lib_Book_LookUp.libId
  JOIN Book_Copies ON Lib_Book_Lookup.bookBarcode = Book_Copies.Barcode
  JOIN Books ON Book_Copies.BookId = Books.ID
GROUP BY 
  Libraries.Name, 
  Books.BookName

答案 1 :(得分:1)

关于数据库设计,您不需要在查找表上使用代理键。您可以简单地执行库的复合主键并预订:

Lib_Book_LookUp
libId bookId
1     1
1     2
2     1
2     2

我使用您的图书ID进行了以下更改(力学和生物学具有相同的ID):

Books
ID  Book ID  BookName
1   1        Fundamentals of calculus
2   2        Mechanics 
3   1        Fundamentals of calculus
4   3        Biology

在第一个查询中,您没有指定语句引用的表(FROM books):

SELECT COUNT(bookId)
FROM books                                       <= Table Reference
WHERE BookName = "Fundamentals of calculus";

在第二个查询中,您使用隐式语法来连接表。您应该像这样练习显式连接:

SELECT Lib_Book_LookUp.libId, Libraries.Name
FROM Lib_Book_LookUp
INNER JOIN Libraries ON Libraries.ID = Lib_Book_LookUp.libId
WHERE bookId IN 
    (SELECT DISTINCT bookId
    FROM books
    WHERE BookName = "Fundamentals of calculus")

此查询加入LibrariesLib_Book_LookUp表,然后查找正在搜索该书的bookId的库。

See it in action

答案 2 :(得分:-1)

您的图书表看起来更像是“图书实例”表格。因此,它不应该有书名。无论是那个,还是BookID列都是多余的。

您的第二个查询是正确的,如果您从1988年编写SQL 。如果没有,您应该使用join语法。