1

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

Table Books
Book_Id INT, PK
Book_Name varchar


Table Tags
Tag_Id INT, PK
Tag_Name varchar

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

4

3 回答 3

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
于 2012-11-15T22:42:58.230 回答
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
);

[工作 SQL Fiddle 示例]

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

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

注意事项:

  • 如果您不需要为每个标签存储任何附加信息(即您没有标签描述等),您可以完全省略 TAG 表。
  • 如果您的 DBMS 支持它,请考虑集群BOOK_TAG。无论如何,您只能通过索引访问它,因此您可以删除“不必要的”表堆。
  • 同样,如果您的 DBMS 支持它,请压缩索引的前沿(BOOK_TAG PK 和 BOOK_TAG_IE1),以节省重复值的空间,更重要的是,提高缓存效率。
于 2012-11-16T00:52:17.863 回答
0

我会制作第三张桌子并使 Book > Tags 成为多对多关系。

所以:

表 Book_Id INT、PK Book_Name varchar

表标签 Tag_Id INT、PK Tag_Name varchar

表 BookTags Id INT、PK Book_Id INT Tag_Id Int

于 2012-11-15T22:44:30.863 回答