2

我有一个存储帖子的表“宝石”(例如博客)。对帖子的回复也存储在同一个表中,其中一个字段存储父帖子的键。每个帖子都可以附加文件。

我需要获取带有相关回复和附加文件的帖子列表。因此,'gems' 有多个 LEFT JOINS 到它 - 一个到它自己,一个到带有文件名的 'gemdetail'。此查询有效:

SELECT g.gemid as gemidx, g.title, gemdetail.filename, r.gemid as rgemid, r.title, r.filename
FROM (SELECT * FROM gems WHERE gems.grade = '7' LIMIT 0, 10) g 
LEFT JOIN (SELECT x.title, x.gemid, x.replygemid, y.filename from gems x 
    LEFT JOIN gemdetail y ON x.gemid = y.gemid ) r ON g.gemid = r.replygemid 
LEFT JOIN gemdetail ON g.gemid = gemdetail.gemid 

但是,如果我每个帖子有 20 个回复和 10 个文件,则返回的记录数是每个帖子 200 条。LIMIT 子句有效,但这仍然是很多记录。加上处理记录集是一种负担。

我重写了查询以使用 UNION,每个帖子仅返回 40 条记录(而不是 200 条)。UNION 有 4 个部分 - 1) 返回前 10 条记录 (LIMIT) 2) 获取帖子的文件名 3) 获取回复 4) 获取回复的文件名

下面的 UNION 查询有效,除了我不能限制 UNION 第一部分以外的任何返回记录的数量。我可以将 LIMIT 语句放入 UNION 的每个部分,但这是不正确的(我想将文件和回复限制在 LIMITed 10 个帖子的集合中)。当我尝试对任何 UNIONS 使用 WHERE gemid IN (SELECT gemid from gems....) 子句时,我得到 mySQL 子查询限制错误。

SELECT g.gemid as gemidx, g.title, NULL as filename, NULL as rgemid, 'ag' as flag 
FROM (SELECT * FROM gems WHERE ISNULL(gems.replygemid) AND gems.grade = '7' LIMIT 0, 10) g
LEFT JOIN (SELECT * FROM gems) r ON g.gemid = r.replygemid  

UNION SELECT g.gemid as gemidx, g.title, gemdetail.filename as filename, NULL as rgemid, 'bf' as flag 
FROM (SELECT * FROM gems WHERE ISNULL(gems.replygemid) AND gems.grade = '7') g 
INNER JOIN gemdetail ON g.gemid = gemdetail.gemid

UNION SELECT g.replygemid as gemidx, g.title, NULL as filename, g.gemid as rgemid, 'cr' as flag 
FROM (SELECT * FROM gems WHERE NOT ISNULL(gems.replygemid) AND gems.grade = '7') g 

UNION SELECT g.replygemid as gemidx, g.title, gemdetail.filename as filename, g.gemid as rgemid, 'df' as flag 
FROM (SELECT * FROM gems WHERE NOT ISNULL(gems.replygemid) AND gems.grade = '7') g 
INNER JOIN gemdetail ON g.gemid = gemdetail.gemid 

ORDER BY gemidx desc, rgemid, flag

请帮忙。有没有办法有效地选择(为了分页)仅 10 个帖子及其所有相关的回复和文件?感谢您花时间阅读本文。我已经为此花了 2 天时间,并且处于我的极限(糟糕的双关语......)。

4

1 回答 1

0

有点玩,但这段代码有点讨厌,所以你可能不想使用它。不过,这暂时忽略了文件。请注意,我在我的一张桌子上得到了类似的东西,然后从中得出了这个,但我没有直接测试过,所以可能有错别字。

SELECT gems.gemid as gemidx, gems.title, r.gemid as rgemid, r.title, r.filename
FROM gems
INNER JOIN (SELECT gems.*, @runningtotal:=@runningtotal+1 AS CurrentTotal
FROM (SELECT @runningtotal := 0)Deriv1, gems 
ORDER BY replygemid) r
INNER JOIN (SELECT replygemid, MIN(CurrentTotal) AS MinTotal
FROM (SELECT replygemid, @runningtotal:=@runningtotal+1 AS CurrentTotal
FROM (SELECT @runningtotal := 0)Deriv1, gems 
ORDER BY replygemid) Deriv2
GROUP BY replygemid) Deriv5
ON Deriv4.replygemid = Deriv5.replygemid 
AND Deriv4.CurrentTotal < Deriv5.MinTotal + 10
WHERE gems.grade = '7'

这样做是使用子选择将序列号添加到回复(由父级排序)。它使用此子选择两次,一次获取组的最小序列号,然后再次带回具有序列号的所有行详细信息。然后将其加入以获取序列号是该 gem 的前 10 个之一的那些。

虽然我更喜欢将内容保存在单个 SQL 中,但我认为这已经到了太慢而不值得的阶段。

可以将文件详细信息放入使用 GROUP_CONCAT 将它们全部添加以进行 gem 回复,然后在您的代码中处理您不感兴趣的那些(即超过 10 个)

抱歉,我想不出更有用的东西

于 2012-12-03T13:34:10.800 回答