我正在尝试从头开始创建一个论坛,主要是为了练习,以后可能会重复使用
我目前正在研究数据库,有一件事让我烦恼。我有一个表格线程,必须包含第一篇文章,作者等的引用...但我不知道如何正确地做到这一点。
(1)我的第一个想法是“让更少的dupplicates成为可能”,所以我想我会有一个基本的Thread表
CREATE TABLE Thread(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
title VARCHAR(40) NOT NULL,
category VARCHAR(40) NOT NULL,
);
和表格帖子
CREATE TABLE Post(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
author VARCHAR(40) NOT NULL,
thread INT NOT NULL,
creationDate DATETIME NOT NULL,
content TEXT NOT NULL,
PRIMARY KEY (id),
CONSTRAINT fk_Post-author_UserProfile-name FOREIGN KEY (author)
REFERENCES UserProfile(name) ON UPDATE CASCADE,
CONSTRAINT fk_Post-thread_Thread-id FOREIGN KEY (thread)
REFERENCES Thread(id)
);
所以,当我想知道一个帖子的第一篇文章时,我会检索该日期中按日期排序的所有帖子并取第一篇。 EZ钱!但后来我想,如果我想得到一个线程,它的作者和创作日期(这对我来说似乎非常合理)知道它的标题,那将是一个带有连接的巨大查询,可能会非常缓慢和繁琐。
SELECT Thread.title, posts.creator, posts.creationDate
FROM Thread
JOIN (
SELECT Post.thread as thread, Post.creationDate, UserProfile.name AS creator
FROM Post
JOIN UserProfile
ON Post.author = UserProfile.id
) AS posts
ON Thread.id = posts.thread
WHERE Thread.title = 'Boy, that''s one hell of a query you''ve got here !'
ORDER BY creationDate
LIMIT 1;
(我不确定这个问题,我是新手)
(2)“好吧那么!只需将'firstPost'列添加到Thread表中”你会告诉我,但那么为什么不复制作者参考?这会停在哪里?
我的猜测是选项(1)太重了,也许和选项(2)只是对第一篇文章的引用可能是更好的选择,但不能直接将作者引用复制到Thread表上。如果我没有误会,应该给出类似下面的内容,但是添加了一个列。
SELECT Thread.title, UserProfile.name, Post.creationDate
FROM Thread
JOIN Post
ON Thread.firstPost = Post.id
JOIN UserProfile
ON Post.author = UserProfile.id
WHERE Thread.title = 'Boy, that''s one hell of a query you''ve got here !';
您如何看待它,请记住,作为一个教学项目,我不仅希望它能够发挥作用,而且还要“干净”?
答案 0 :(得分:1)
你的初始直觉是正确的 - 不要复制数据,除非你真的需要。你的查询真的不复杂。并且,维护重复数据非常复杂。
您的第一个查询应该是:
SELECT t.title, up.name as creator, p.creationDate
FROM Thread t JOIN
Post p
ON p.thread = t.id JOIN
UserProfile up
ON p.author = up.id
WHERE t.title = 'Boy, that''s one hell of a query you''ve got here !'
ORDER BY p.creationDate
LIMIT 1;
注意:
FROM
子句中使用子查询。你并不需要。threadId
代替id
和thread
。答案 1 :(得分:1)
我理解你的想法。是的,一个帖子由一系列帖子组成,但第一篇帖子与其他帖子不同,因为这是主题的内容,而其他帖子仅仅是对第一篇帖子的回复。
从这个角度来看,我们可以争辩说,不仅帖子属于一个帖子(因此一个帖子表必须包含线程ID),而且该帖子也是一个(第一个)帖子,因此应该包含帖子ID。这是一个可能的模型,但导致了一个鸡蛋和鸡蛋问题:每个帖子必须属于一个现有的帖子,每个帖子必须引用一个现有的帖子。可以通过编写没有post引用的线程来解决这个问题,然后编写第一篇文章,然后更新线程。哪个会起作用,但不是一个优雅的解决方案。另一种选择是在一个事务中写入两个记录(已经包含帖子ID的线程;包含线程ID的帖子),并且约束仅适用于提交。这称为延迟约束,仅在少数DBMS中可用。我很确定,MySQL不支持这些。
但是当然你可以保持简单,说一个帖子和数据模型中的另一个帖子一样好,一个恰好是第一个。这就是你已经拥有的并没有错。这是一个有效的模型。但是,我建议使用带有coumpound键和帖子号而不是ID的模型:
其中主键为粗体。第一篇文章当然是post_num
1,第二篇文章是#2,依此类推。这将使得检索线程的第一个帖子变得非常简单。
但是还有另一件事想到了。在许多论坛中,线程不包含帖子的链,而是帖子的树。这意味着:除第一个帖子外,帖子总是指其回复的另一个帖子。这可能导致以下模型:
因此,post表中的记录可以引用post表中的另一条记录(它回复的帖子)。复合键带来了另一个优势:post_num
和parant_post_num
只与thread_id
结合使用。所以约束FOREIGN KEY (thread_id, parent_post_num) REFERENCES (thread_id, post_num)
会很好用,因为帖子在外部线程中没有父帖子(它可以使用非复合键)。