2016-04-25 53 views
0

我想为我的网站创建一个新闻源,显示3种类型的信息:问题,答案(与问题相关)和讨论。SQL - 多个联接(新闻源)

我有一个称为活动的主表记录了平台的所有活动,并为每种类型的记录(用户,问题解答和讨论)的一个单独的表,如下图所示:

表活动

EventID EventType fkQuestionID fkAnswerID fkDiscussionID 
1  Question 1    NULL   NULL 
2  Question 2    NULL   NULL 
3  Discussion NULL   NULL   1 
4  Answer  1    1   NULL 
5  Question 3    NULL   NULL 
6  Discussion NULL   NULL   2 
7  Answer  2    2   NULL 
8  Discussion NULL   NULL   3 

表问题

QuestionID fkUserID QuestionTitle 
1   1   Who is Homer Simpson? 
2   2   What is the capital of Madagascar? 
3   3   What superpower would you choose? 

表问答

AnswerID fkQuestionID fkUserID Answer 
1   1    2   He is a characted of a... 
2   2    4   The capital is... 

圆桌讨论

DiscussionID fkUserID DiscussionTitle 
1    3   The best day of my life 
2    1   The worst zombie movies 
3    2   The funiest scens of... 

表用户

UserID Name 
1  Jack 
2  Ana 
3  Rose 
4  Brad 

这是预期的结果:

enter image description here

到目前为止,我创建了以下查询:

SELECT E.EventID, 
E.EventType, 
E.fkQuestionID, 
E.fkAnswerID, 
E.fkDiscussionID, 
Q.QuestionTitle, 
U1.Name as QuestionBy, 
A.Answer, 
U2.Name as AnswerBy, 
D.DiscussionTitle, 
U3.Name as PostBy 
FROM events E 
LEFT JOIN questions Q ON Q.QuestionID=E.fkQuestionID 
LEFT JOIN users U1 ON U1.UserID=Q.fkUserID 
LEFT JOIN (
SELECT fkQuestionID, MAX(AnswerID) AS AnswerID 
FROM answers 
GROUP BY fkQuestionID 
) t ON t.fkQuestionID = E.fkQuestionID //show the last answer 
LEFT JOIN answers A ON A.pkAnswerID = t.AnswerID 
LEFT JOIN users U2 ON U2.UserID=A.fkUserID 
LEFT JOIN dicussions D ON D.DiscussionID=E.fkDiscussionID 
LEFT JOIN users U3 ON U3.UserID=D.fkUserID 

鉴于表事件将存储大量行的,我在怀疑一些事情,也关于慢的性能:

  • 当前查询已经采取+ 2S工艺( 30行)。由于我正在制作一种新闻馈送页面,而不是一次对所有数据进行大量查询,因此我正在考虑使用一个循环并进行几个单独的查询来为每种类型的事件带来其余信息并使用ajax加载它(减少服务器响应并增加页面加载的印象)。这是一个愚蠢的想法?

  • 对于与表用户的连接,有没有更好的方法,而不是对每种类型的事件使用许多左连接(U1,U2,U3)?我害怕在所有类型的事件中使用许多左连接。

  • 如果有人写了一个新的答案,我试着只带上与该问题有关的最后一个Answer(max AnswerID)。但是,我正在努力隐藏与同一问题相关的其他事件(以避免同一问题的重复供稿/事件)。有谁知道我该如何解决这个问题?

+0

请发布纯文本,而不是图像,所以我们可以复制并粘贴到sqlfiddle。 – Barmar

+2

你不能写条件连接。你通常所做的就是编写多个查询,每个查询都与不同的表连接,并将它们与'UNION'结合起来。 – Barmar

+0

@Barmar:编辑为纯文本,tks! – czmarc

回答

1

我个人根本没有看到事件表的理由。

我会通过A UNION ALL查询解决这个问题,我会将问题和答案链接到查询的同一行。例如:

SELECT 
'Question' as EventType, 
Q.QuestionID, 
t.AnswerID, 
NULL as DiscussionID, 
Q.QuestionTitle, 
U1.Name as QuestionBy, 
A.Answer, 
U2.Name as AnswerBy, 
NULL as DiscussionTitle, 
NULL as PostBy 
FROM questions Q 
JOIN users U1 ON U1.UserID=Q.fkUserID 
LEFT JOIN (
SELECT fkQuestionID, MAX(AnswerID) AS AnswerID 
FROM answers 
GROUP BY fkQuestionID 
) t ON t.fkQuestionID = Q.QuestionID 
LEFT JOIN answers A ON A.pkAnswerID = t.AnswerID 
LEFT JOIN users U2 ON U2.UserID=A.fkUserID 


UNION ALL 

SELECT 
'Discussion' as EventType, 
NULL, 
NULL, 
NULL, 
NULL, 
NULL, 
NULL, 
NULL, 
D.DiscussionTitle, 
U3.Name as PostBy 
FROM dicussions D 
LEFT JOIN users U3 ON U3.UserID=D.fkUserID 

当然,您可能想要限制某个用户的where子句。如果你想要他们回答的问题以及他们提出的问题,那么当你按用户看时,再添加另一个UNION ALL。

在这一点上,你还应该检查你的索引,以确保你在所有的连接字段上都有它们。

+0

不错,使用UNION ALL(0.7s)可以更快地工作。但是,即使使用表答案的左加入,该查询只会带来已回答的问题。我怎样才能适应也带来未解答的问题? – czmarc

+0

并将EventType作为问题(未回答)和答案 – czmarc

+1

不同,我使用另一个UNION与表问题一起解决并检索未答复的问题 – czmarc