我必须通过标签来定义书的属性,我正在考虑创建表格
Table Books
Book_Id INT, PK
Book_Name varchar
Table Tags
Tag_Id INT, PK
Tag_Name varchar
一本书可以有多个标签,如恐怖、有趣、黑暗等。我如何定义一本书与其所有标签之间的一对多关系?
我必须通过标签来定义书的属性,我正在考虑创建表格
Table Books
Book_Id INT, PK
Book_Name varchar
Table Tags
Tag_Id INT, PK
Tag_Name varchar
一本书可以有多个标签,如恐怖、有趣、黑暗等。我如何定义一本书与其所有标签之间的一对多关系?
您需要在书籍和标签之间创建一个连接表,如下所示:
Books_Tags Table
Book_id int -- will be PK
Tag_ig int -- will be PK
连接表的主键将包含两个字段 (book_id
和tag_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
考虑使用自然键(而不是代理“标签 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
);
如您所见,只有一个 JOIN(这里写为 IN)。搜索书籍(或仅显示标签名称 - 此处未显示)时,根本不需要加入 TAG 表。
进行第二次 JOIN 的唯一原因是如果/何时需要从 TAG 表中获取这些“其他字段”。
我会制作第三张桌子并使 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