2012-04-17 136 views
7

我有两个表格:tableA (idA, titleA)tableB (idB, idA, textB),它们之间有一对多的关系。对于tableA中的每一行,我想检索tableB中对应的最后5行(由idB排序)。每组获得第一/最后n条记录

我已经试过

SELECT * FROM tableA INNER JOIN tableB ON tableA.idA = tableB.idA LIMIT 5 

,但它只是限制内蒙古全球结果JOIN,而我想限制结果为每个不同的tableA.id

我怎么能这样做?

由于

+0

对于最后5个...是否有基于表B中的最后5个,或只是基于“idB”的最后5个,这将看起来是一个自动增量序列列。如果是基于日期的话,那么这个列将是... – DRapp 2012-04-17 12:42:41

+0

它基于idB,自动递增。 – 2012-04-17 12:58:18

+0

Similar questions:http://stackoverflow.com/questions/4688664/mysql-select-n-records-base-on-group-by和http://stackoverflow.com/questions/5319643/top-n-per- group-with-multiple-table-joins,也许http://stackoverflow.com/q/7539548- [this](http://stackoverflow.com/q/8748986)和[this]的扩展(http:///stackoverflow.com/q/1313120) – TMS 2012-04-17 13:29:38

回答

2

我想这是你所需要的:

SELECT tableA.idA, tableA.titleA, temp.idB, temp.textB 
FROM tableA 
INNER JOIN 
(
    SELECT tB1.idB, tB2.idA, 
    (
     SELECT textB 
     FROM tableB 
     WHERE tableB.idB = tB1.idB 
    ) as textB 
    FROM tableB as tB1 
     JOIN tableB as tB2 
      ON tB1.idA = tB2.idA AND tB1.idB >= tB2.idB 
    GROUP BY tB1.idA, tB1.idB 
    HAVING COUNT(*) <= 5 
    ORDER BY idA, idB 
) as temp 
ON tableA.idA = temp.idA 

有关此方法的更多资讯:

http://www.sql-ex.ru/help/select16.php

+1

为什么你有第三个嵌套select('从tableB中选择textB,其中tableB.idB = tB1.idB')?这个子查询可以用'tB1.textB'替换! – TMS 2012-04-17 16:32:36

+0

并用'join'替换'inner join'。不要让它成为一个比它更大的谜团:-) – TMS 2012-04-17 16:33:44

+2

@ user1336526,我已简化并更正了此Carlos的解决方案,请参阅我的答案。 – TMS 2012-04-17 16:50:55

0

确保您的“B”表具有由目的优化的订单上(IDA,IDB)的索引,从而对于每个“A”的ID,它可以快速地具有“B”降序排列从而把最新的PER每个“A”ID。使用MySQL变量,每当“A”ID发生变化时,它就会重置为下一个“A”ID的等级1。

select 
     B.idA, 
     B.idB, 
     B.textB 
     @RankSeq := if(@LastAGroup = B.idA, @RankSeq +1, 1) ARankSeq, 
     @LastAGroup := B.idA as ignoreIt 
    from 
     tableB B 
     JOIN tableA A 
      on B.idA = A.idA, 
     (select @RankSeq := 0, @LastAGroup := 0) SQLVars 
    having 
     ARankSeq <= 5 
    order by 
     B.idA, 
     B.idB DESC 
+0

呃!令人讨厌的查询:-)看看[更简单的变体](http://stackoverflow.com/a/4688699/684229)。无论如何,性能有一个很大的缺点 - MySQL必须遍历所有行。 – TMS 2012-04-17 17:07:56

0
select * from tablea ta, tableb tb 
where ta.ida=tb.idb and tb.idb in 
(select top 5 idb from tableB order by idb asc/desc) 
  • (ASC,如果你想降低IDS desc如果你想要更高的ID)
  • 那么复杂,易于包括多个条件
  • 如果顶端的语句不存在在MySQL中使用的限制条款(我没有生根粉mysql的很多知识)
+0

他要求tableA中排名前5位的每一行。这只是将tableB限制在前5行,按idb排序。你也需要使用MySQL的LIMIT,而不是TOP。 – Aaron 2012-04-17 21:18:16

+0

感谢您的意见我意识到我的错误......将这项工作....选择*从tablea ta,tableb tb其中ta.ida = tb.idb和tb.idb(从tableB选择idb, tableA tableB.idb = tableA.ida order by idb asc/desc limit 5).. – 2012-04-18 06:30:49

5

大大简化和纠正卡洛斯溶液(他解决方案将返回前5行,不会持续太久...):

SELECT tB1.idA, tB1.idB, tB1.textB 
FROM tableB as tB1 
    JOIN tableB as tB2 
     ON tB1.idA = tB2.idA AND tB1.idB <= tB2.idB 
GROUP BY tB1.idA, tB1.idB 
HAVING COUNT(*) <= 5 

在MySQL中,你可以使用tB1.textB即使是GROUP BY查询,因为你是美洲开发银行第一个表分组,所以每个只有tB1.textB的单个值组...

+0

只是一个注释,只是不要忘记它:它仍然是问题哪个解决方案会更好地形成 - 联接解决方案原则上是二次的,而rank解决方案是线性的。也就是说,SQL优化器很可能会使二次问题降至线性,而排名解决方案无法预期更多优化。这同样适用于[此类似问题]的解决方案(http://stackoverflow.com/q/8748986)。 – TMS 2012-04-17 17:17:48

+0

我在MySQL中的一般经验是,如果你可以重写子查询/排名查询来加入,它会更快。 – TMS 2012-04-17 17:18:55

相关问题