标签的数据库表会是什么样的?

时间:2012-11-15 22:40:55

标签: database-design

我必须通过标签定义book的属性,我正在考虑创建表

Table Books
Book_Id INT, PK
Book_Name varchar


Table Tags
Tag_Id INT, PK
Tag_Name varchar

一本书可以有多个标签,如恐怖,搞笑,黑暗等。我如何定义一本书及其所有标签之间的一对多关系?

3 个答案:

答案 0 :(得分:2)

您需要在书籍和标签之间创建一个连接表,如下所示:

Books_Tags Table
Book_id int   -- will be PK
Tag_ig int    -- will be PK

连接表的主键将包含两个字段(book_idtag_id),这两个字段也是其他表的外键。

然后,当您要查询数据时,您的查询将与此类似:

select *
from books b
left join books_tags bt
  on b.book_id = bt.bookid
left join tags t
  on bt.tag_id = t.tag_id

答案 1 :(得分:2)

考虑使用自然键(而不是代理“标签ID”)来避免在搜索标签时可能需要的JOIN之一(这可能是合理大小的数据库上的性能关键路径)。

例如:

CREATE TABLE BOOK (
    BOOK_ID INT PRIMARY KEY
    -- Other fields...
);

CREATE TABLE BOOK_TAG (
    TAG_NAME VARCHAR(30),
    BOOK_ID INT,
    PRIMARY KEY (TAG_NAME, BOOK_ID),
    FOREIGN KEY (BOOK_ID) REFERENCES BOOK (BOOK_ID) ON DELETE CASCADE
);

-- For enforcing and cascading the FK and for GROUP BY (in the query below).
CREATE INDEX BOOK_TAG_IE1 ON BOOK_TAG (BOOK_ID, TAG_NAME);

CREATE TABLE TAG (
    TAG_NAME VARCHAR(30) PRIMARY KEY,
    -- Other fields...
);

您现在可以获得具有任何给定标签的图书,如下所示:

SELECT *
FROM BOOK
WHERE BOOK_ID IN (
    SELECT BOOK_ID
    FROM BOOK_TAG
    WHERE
        TAG_NAME = 'tag1'
        OR TAG_NAME = 'tag2'
        -- Etc...
);

具有全部给定标签的图书如下:

SELECT *
FROM BOOK
WHERE BOOK_ID IN (
    SELECT BOOK_ID
    FROM BOOK_TAG
    WHERE
        TAG_NAME = 'tag1'
        OR TAG_NAME = 'tag2'
        -- Etc...
    GROUP BY BOOK_ID
    HAVING COUNT(TAG_NAME) = 2
);

[Working SQL Fiddle Example]

如您所见,只有一个JOIN(在此处写为IN)。在搜索图书时(或只显示标签名称 - 此处未显示),根本不需要使用TAG表加入。

进行第二次JOIN的唯一原因是,当你需要从TAG表中获取这些“其他字段”时。

注意事项:

  • 如果您不需要为每个标签存储任何其他信息(即您没有标签说明等),则可以完全省略TAG表。
  • 如果您的DBMS支持,请考虑clustering BOOK_TAG。无论如何,您正在访问它only through indexes,因此您可以删除“不必要的”表堆。
  • 同样,如果您的DBMS支持它,compress索引的前沿(BOOK_TAG PK和BOOK_TAG_IE1),以节省重复值的空间,更重要的是,提高缓存效率。

答案 2 :(得分:0)

我会制作第3张桌子并制作Book>标记多对多的关系。

所以:

表书 Book_Id INT,PK Book_Name varchar

表格标签 Tag_Id INT,PK Tag_Name varchar

Table BookTags Id INT,PK Book_Id INT Tag_Id Int