mysql分页左连接与联盟LIMIT

时间:2012-12-03 10:26:45

标签: mysql pagination left-join limit union

我有一个表'gems'存储帖子(例如博客)。对帖子的回复也存储在同一个表中,其中包含存储父帖子密钥的字段。每个帖子都可以附加文件。

我需要获得一个包含相关回复和附件的帖子列表。 '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(来自gems的SELECT gemid ....)子句时,我得到了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个帖子及其所有相关的回复&文件?感谢您抽出宝贵时间阅读本文。我花了两天时间在这上面,并且在我的极限(糟糕的双关语......)。

1 个答案:

答案 0 :(得分: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'

这样做是使用子选择向回复添加序列号(由父级排序)。它使用此子选择两次,一次获取组的最小序列号,然后再次使用序列号返回所有rowdetails。然后将其连接到那些序列号是该宝石的前10个之一的那些。

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

可以使用GROUP_CONCAT将文件详细信息添加到gem回复中,然后在代码中处理您不感兴趣的文件(即超过10个)

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

相关问题