我有一个当前正在使用嵌套选择的MySQL查询,我想知道是否可以重写查询以不使用嵌套选择,如果是这样的话?
查询如下
SELECT
b.id,
b.name,
b.description,
b.order,
b.icon,
b.locked,
u.username AS lastPoster,
p.time AS lastPostTime,
p1.subject AS lastPostTopicSubject,
p2.postscount AS totalPosts,
t1.topicscount AS totalTopics,
p.subject AS lastPostSubject,
t.id AS lastPostTopicId
FROM kf_boards AS b
LEFT JOIN kf_topics AS t ON (t.boardid = b.id)
LEFT JOIN (SELECT posterid, topicid, time, subject
FROM kf_posts
ORDER BY time DESC) AS p ON (p.topicid = t.id)
LEFT JOIN (SELECT subject
FROM kf_posts
ORDER BY time ASC) AS p1 ON (p.topicid = t.id)
LEFT JOIN (SELECT COUNT(id) AS postscount
FROM kf_posts) AS p2 ON (p.topicid = t.id)
LEFT JOIN (SELECT COUNT(id) AS topicscount
FROM kf_topics) AS t1 ON (t.boardid = b.id)
LEFT JOIN kf_users AS u ON (p.posterid = u.id)
WHERE b.categoryid = :catid
GROUP BY b.name
ORDER BY b.order
数据库结构如下
任何帮助都会非常受欢迎!
谢谢!
编辑:尝试在查询下方,结果返回
结果应如下
答案 0 :(得分:0)
尝试:
SELECT
b.id, b.name, b.description, b.order, b.icon, b.locked,
u.username AS lastPoster, p.time AS lastPostTime,
p.subject AS lastPostSubject, t.id AS lastPostTopicId
FROM kf_boards AS b
LEFT JOIN kf_topics AS t ON t.boardid = b.id
LEFT JOIN kf_posts AS p ON p.topicid = t.id
LEFT JOIN kf_users AS u ON p.posterid = u.id
WHERE b.categoryid = :catid
GROUP BY b.name
ORDER BY b.order ASC, p.time DESC
SELECT b.id, b.name, b.description, b.order, b.icon, b.locked,
u.username AS lastPoster, MAX(p.time) AS lastPostTime,
p.subject AS lastPostTopicSubject, count(p.id) AS totalPosts,
count(t.id) AS totalTopics, p.subject AS lastPostSubject,
max(t.id) AS lastPostTopicId
FROM kf_boards AS b
LEFT JOIN kf_topics AS t ON t.boardid = b.id
LEFT JOIN kf_posts AS p ON p.topicid = t.id
LEFT JOIN kf_users AS u ON p.posterid = u.id
WHERE b.categoryid = :catid
GROUP BY b.name, b.id, b.name, b.description, b.order, b.icon,
b.locked, u.username, p.subject
ORDER BY b.order
答案 1 :(得分:0)
似乎可以删除所有子查询, 但是如果最后一个帖子和第一个帖子就相应的话,查询会更清楚 使用子查询找到主题:
SELECT b.id, b.name, b.description, b.sortorder, b.icon, b.locked,
u.username AS lastPoster,
p1.time AS lastpostTime,
p0.subject AS lastPostTopicSubject,
COUNT(DISTINCT p.id) AS totalPosts,
COUNT(DISTINCT t.id) AS totalTopics,
p1.subject AS lastPostSubject,
p1.topicid AS lastPostTopicId
FROM kf_boards b
LEFT JOIN kf_topics t ON t.boardid = b.id
LEFT JOIN kf_posts p ON p.topicid = t.id
LEFT JOIN kf_posts p1
ON p1.time = (SELECT MAX(time) FROM kf_posts p
INNER JOIN kf_topics t
ON p.topicid = t.id
WHERE t.boardid = b.id)
LEFT JOIN kf_users u ON u.id = p1.posterid
LEFT JOIN kf_posts p0
ON p0.time = (SELECT MIN(time) FROM kf_posts p0
WHERE p0.topicid = p1.topicid)
WHERE b.categoryid = :catid
GROUP BY b.id
ORDER BY b.sortorder;
但是,以下查询使用自联接查找没有相关先前/嵌套帖子的帖子应该给出相同的答案:
SELECT b.id, b.name, b.description, b.sortorder, b.icon, b.locked,
u.username AS lastPoster,
lastpost.time AS lastpostTime,
firstpost.subject AS lastPostTopicSubject,
COUNT(DISTINCT p.id) AS totalPosts,
COUNT(DISTINCT t.id) AS totalTopics,
lastpost.subject AS lastPostSubject,
lastpost.topicid AS lastPostTopicId
FROM kf_boards b
LEFT JOIN kf_topics t ON t.boardid = b.id
LEFT JOIN kf_posts p ON p.topicid = t.id
LEFT JOIN kf_topics lasttopic ON lasttopic.boardid = b.id
LEFT JOIN kf_posts lastpost ON lastpost.topicid = lasttopic.id
LEFT JOIN kf_topics nexttopic ON nexttopic.boardid = b.id
LEFT JOIN kf_posts nextpost -- order posts
ON nextpost.topicid = nexttopic.id -- in same board
AND nextpost.time > lastpost.time -- by time
LEFT JOIN kf_users u ON u.id = lastpost.posterid
LEFT JOIN kf_posts AS firstpost ON firstpost.topicid = lastpost.topicid
LEFT JOIN kf_posts prevpost -- order posts
ON prevpost.topicid = firstpost.topicid -- on same topic
AND prevpost.time < firstpost.time -- by time
WHERE nextpost.id IS NULL -- last post has no next
AND prevpost.id IS NULL -- first post on topic has no previous
AND b.categoryid = :catid
GROUP BY b.id
ORDER BY b.sortorder;
的结果
答案 2 :(得分:0)
这是一个可能有所帮助的解决方案,但是,我还有其他建议可以通过触发器简化所有查询。我稍后会解释。
我从最内层的查询开始,仅针对类别(您的参数)的电路板ID以及电路板有HAS POSTINGS(不是通过LEFT-JOIN)。从这一点来看,无论主题如何,我都会获得每个主板的最大帖子ID(只是它必须是每个连接的有效板)。
一旦我有了,下一个查询将根据最后一篇帖子重新加入posts表以确定主题...然后在同一主题ID上再次重新加入帖子。有了这个,我可以获得该主题的第一个帖子ID和总条目...所有按“板ID”分组。
这些显然只是拥有至少1板的板子,但这不是你想要的。你想要所有的董事会,无论一个帖子。所以,我回到开头再次使用相同的WHERE查询kf_boards类别ID =您的参数......这将为您提供该类别的所有电路板......
现在,您可以左键加入到最终/最大帖子和条目计数的预聚合查询...然后再次离开加入到帖子表但是TWICE ...一次为第一篇帖子(所以你可以获得最初的主题标题,时间和你可能关心的任何其他内容),以及为最后的POST获取时间,主题等...你已经拥有了这个主题的总帖子条目聚合查询。最后,在用户表的最后一个帖子上进行左连接,以查看最后发布的帖子。
我已经测试了它的语法并且它可以工作,根据实际数据无法确认。
SELECT
B.ID,
B.Name,
B.Description,
B.Order,
B.Icon,
FP.Subject as FirstPostSubject,
FP.Time as FirstPostTime,
LP.Subject as LastPostSubject,
LP.Time as LastPostTime,
U.UserName as LastPostUserName,
QryPerBoard.PostEntries
from
kf_boards B
LEFT JOIN
( select
PQ1.ID,
PQ1.LastPostID,
MIN( P2.ID ) as FirstPostID,
COUNT(*) as PostEntries
from
( SELECT
B1.ID,
MAX( P1.ID ) as LastPostID
from
kf_boards B1
join kf_topics T1
ON B1.ID = T1.BoardID
join kf_posts P1
ON T1.ID = P1.TopicID
where
B1.CategoryID = 1 <-- Insert your Category Parameter ID here
group by
B1.ID ) as PQ1
LEFT JOIN kf_posts P1
ON PQ1.LastPostID = P1.ID
LEFT JOIN kf_posts P2
ON P1.TopicID = P2.TopicID
group by
PQ1.ID ) QryPerBoard
ON B.ID = QryPerBoard.ID
LEFT JOIN kf_posts FP
ON QryPerBoard.FirstPostID = FP.ID
LEFT JOIN kf_posts LP
ON QryPerBoard.LastPostID = LP.ID
LEFT JOIN kf_users U
ON LP.PosterID = U.ID
where
B.CategoryID = 1 <-- Insert your Category Parameter ID here (second copy for parameter)
现在,我将如何调整以防止递归级别的查询,尤其是对于网站。使用触发器。创建并保存POST时,请使用触发器执行一些操作...
修改了关于触发影响的思考。
使用最新的主题ID更新kf_Boards,为任何相应的主板ID创建任何帖子,这样您以后就不必再寻找它,只需采取最后一个并随之运行。此外,更新TOPIC记录。为主题提供第一个帖子,最后一个帖子和总帖子的列。如果是该主题的第一篇帖子,请使用新ID更新第一篇和最后一篇文章,并增加总帖子数。
合并这些触发器以更新“额外”列的时间将为将来的查询节省这些复杂性。你基本上可以做类似
的事情select
B.*,
LP.Fields, <obviously apply specific fields you want per table>
FP.Fields,
U.Fields
from
kf_boards B
LEFT JOIN kf_topics T
on B.LastTopicID = T.ID
LEFT JOIN kf_posts FP
on T.FirstPostID = FP.ID
LEFT JOIN kf_posts LP
on T.LastPostID = LP.ID
LEFT JOIN kf_users U
on LP.PosterID = U.ID
where
B.CategoryID = 1 <-- your parameterID