SQL从最近的四个集合中获取两个项目

时间:2011-11-01 19:01:21

标签: mysql sql innodb greatest-n-per-group

是的,这可能是另一个问题......但是我已经尝试了至少十几个已经在这里发布的问题的答案,找不到一个适用于我正在努力的问题做。这可能是我想要忽视的东西,或者我想要的只是略有不同。可能是第一个:/

我有两个表(InnoDB),一个用于图像集,每组一行,其中包含一些信息,如set_title,链接到的产品,开/关状态和dateadded:

图库集

  • set_id(primary)
  • product_id(外键)
  • set_title(varchar 128)
  • set_status(enum online / offline,index)
  • set_dateadded(datetime,index)

每个图像的表格,每个图像都有一个或多个图像。虽然没有路径字段,我只是使用它有点像set_id / pic_id.jpg ...还有一些其他字段,如viewcounts等,但这些问题不需要,所以我把它们留了出来。

GalleryPics

  • pic_id(主要)
  • set_id(主要,外键)
  • pic_dateadded(datetime,index)

基本上我想为最新的4套显示2张图片。我在下面有这个查询接近我想要的,它唯一不做的就是将它限制为每组2个:

SELECT s.`set_id`, s.`set_title`, s.`set_dateadded`, p.`pic_id`, p.`pic_dateadded`
FROM `GallerySets` s
LEFT JOIN `GalleryPics` p
ON (s.`set_id` = p.`set_id`)
WHERE s.set_status = 'online'
ORDER BY s.`set_dateadded` DESC, p.`pic_dateadded` ASC

它只是显示了一切。在其他问题(如this one)中,我看到改变在线并添加HAVING应该可以做到这一点:

ON (s.`set_id` = p.`set_id` AND s.`set_dateadded` < p.`pic_dateadded`)
HAVING COUNT(*) < 3

我已经尝试了各种各样的变种与HAVING,但它并没有让我更接近。它实际上返回零结果或每组一行,只要我添加任何类型的HAVING行。也许我正在尝试使用错误的最大n组解决方案?也许是因为我想对datetime字段进行排序而不是自动递增ID?

通缉结果

实际上想要更像是最近五集的前三张照片,但是为了给出一个不太长的结果例子......稍微调整一下。

set_id | set_title | set_dateadded         | pic_id | pic_dateadded
4      | blah4     | 2011-10-04 00:00:00   | 32     | 2011-10-04 12:44:01
4      | blah4     | 2011-10-04 00:00:00   | 33     | 2011-10-04 12:44:02
3      | blah3     | 2011-10-03 00:00:00   | 26     | 2011-10-03 12:33:01
3      | blah3     | 2011-10-03 00:00:00   | 27     | 2011-10-03 12:33:02
2      | blah2     | 2011-10-02 00:00:00   | 11     | 2011-10-02 12:22:01
2      | blah2     | 2011-10-02 00:00:00   | 12     | 2011-10-02 12:22:02
1      | blah1     | 2011-10-01 00:00:00   | 1      | 2011-10-01 12:11:01
1      | blah1     | 2011-10-01 00:00:00   | 2      | 2011-10-01 12:11:02

开始认为让一个查询获得最新集合然后在php中使用while循环获取最新集合可能不是最糟糕的想法,以获得每个集合的几个图片。 :/


解决方案

感谢George Psarakis的工作解决方案。这显示了最近四组中的前两张照片:

SET @rownum=0;
SET @last_group_id=0;
SELECT gp.pic_id, gp.pic_dateadded, gs.*,
@rownum:=IF(gp.set_id<>@last_group_id,1,@rownum+1) AS rn, @last_group_id:=gp.set_id
FROM GalleryPics gp JOIN 
(
  SELECT * FROM GallerySets WHERE set_status='online'
  ORDER BY gs.set_dateadded DESC LIMIT 5
) AS gs
ON gs.set_id = gp.set_id 
HAVING rn < 4
ORDER BY gs.set_dateadded DESC, gp.pic_dateadded ASC

(对于900多套和10000多张照片,查询时间约为0.0030秒)

1 个答案:

答案 0 :(得分:0)

我不太确定,但你可以试试以下吗?

SET @rownum=0;
SET @last_group_id=0;
SELECT * FROM (
  SELECT gp.*,gs.*,@rownum:=IF(gp.set_id<>@last_group_id,1,@rownum+1) AS rn,
  @last_group_id:=gp.set_id FROM GalleryPics gp JOIN 
  (
    SELECT * FROM GallerySets WHERE set_status='online' 
    ORDER BY set_dateadded DESC LIMIT 4
  ) AS gs
  ON gs.set_id = gp.set_id 
  GROUP BY gp.set_id 
  ORDER BY gp.set_id,gp.pic_dateadded 
) tmp WHERE rn < 3