4

我试图在 GROUP BY 中获取记录的子集,我已经看到了很多疯狂的解决方案,但它们似乎太复杂了,有没有更有效的方法来做到这一点。

SELECT user_id, GROUP_CONCAT(item_id ORDER BY `timestamp`) AS items 
FROM wb_user_book_current_item GROUP BY user_id

因此,这将为我返回所有用户的所有当前项目,到目前为止还可以。但我只想要最近的十个项目。添加ORDER BYGROUP_CONCAT帮助中,但它仍然没有给我最后十条记录。

编辑

如果我做这样的事情并硬编码,user_id那么我可以获得我想要的那个用户的结果,问题是组合它,这样我就不需要硬编码user_id,例如可以让所有用户最后十个项目

SELECT GROUP_CONCAT(cp2.item_id) AS items 
FROM (SELECT cp.user_id, cp.item_id 
      FROM wb_user_book_current_item cp 
      WHERE cp.user_id=1 ORDER BY cp.`timestamp` 
      LIMIT 10) AS cp2 
GROUP BY cp2.user_id
4

5 回答 5

5

这是一个难题,但是如何:

SELECT user_id, GROUP_CONCAT(item_id ORDER BY `timestamp`) AS items
FROM wb_user_book_current_item T
WHERE NOT EXISTS
(
    SELECT 1
    FROM wb_user_book_current_item T2
    WHERE T2.user_id = T.user_id
    ORDER BY T2.`timestamp` DESC
    LIMIT 10,1
) 
OR T.`timestamp` > (
    SELECT T2.`timestamp`
    FROM wb_user_book_current_item T2
    WHERE T2.user_id = T.user_id
    ORDER BY T2.`timestamp` DESC
    LIMIT 10,1
)
GROUP BY user_id

这当然假设您不会timestamp为同一用户提供两行相同的行。

如果您的时间戳字段始终为正整数,您还可以将 替换NOT EXISTS...ORCOALESCE

SELECT user_id, GROUP_CONCAT(item_id ORDER BY `timestamp`) AS items
FROM wb_user_book_current_item T
WHERE T.`timestamp` > COALESCE((
    SELECT T2.`timestamp`
    FROM wb_user_book_current_item T2
    WHERE T2.user_id = T.user_id
    ORDER BY T2.`timestamp` DESC
    LIMIT 10,1
), 0)
GROUP BY user_id

原始答案,但显然 MySQL 不明白如何正确执行此操作并抱怨子选择返回多行。当然我们想要多行;这是一个GROUP_CONCAT。Grr。

不幸的是,我认为使用子查询没有真正的方法:

SELECT T.user_id, 
    GROUP_CONCAT((SELECT T2.item_id 
                  FROM wb_user_book_current_item T2 
                  WHERE T2.user_id = T.user_id 
                  ORDER BY T2.`timestamp` 
                  LIMIT 10)) AS items 
FROM wb_user_book_current_item T
GROUP BY user_id

否则,LIMIT在其他任何地方添加将限制组的数量,或者限制表(而不是组)上的总记录集 - 这两者都不是您想要实现的。

于 2012-10-26T17:19:51.003 回答
4

所以在这里遇到了一个很好的解决方案。

http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/

就像这样放在一起:

SET @num := 0, @user_id := '';

SELECT cp2.user_id, CONCAT(cp2.item_id) AS items
FROM (
   SELECT cp.user_id, cp.item_id,
   @num := IF(@user_id = cp.user_id, @num + 1, 1) AS row_number,
   @user_id := cp.user_id AS dummy
   FROM wb_user_curent_item AS cp
   ORDER BY cp.user_id ASC, cp.`timestamp` DESC
) AS cp2 WHERE cp2.row_number <= 10
GROUP BY cp2.user_id

所以基本上它只是使用num增量来限制记录而不是使用LIMIT

于 2012-10-26T21:53:47.310 回答
1
SELECT 
    i.user_id,
    GROUP_CONCAT(i.item_id ORDER BY i.timestamp) AS items 
FROM 
    ( SELECT DISTINCT user_id
      FROM wb_user_book_current_item 
    ) AS du
  JOIN
    wb_user_book_current_item AS i
      ON  i.user_id = du.user_id
      AND i.timestamp <= COALESCE(
          ( SELECT i2.item_id 
            FROM wb_user_book_current_item AS i2
            WHERE i2.user_id = du.user_id
            ORDER BY i2.timestamp ASC 
              LIMIT 1 OFFSET 9
          )
          , '2038-01-19 03:14:07')
GROUP BY
    i.user_id ;

上的索引(user_id, timestamp, item_id)将有助于提高效率。

于 2012-10-26T22:34:16.663 回答
-1

试试这个:

SELECT 
  user_id, 
  GROUP_CONCAT(item_id ORDER BY `timestamp`) AS items 
FROM wb_user_book_current_item 
GROUP BY user_id
LIMIT 0, 10
于 2012-10-26T17:20:15.697 回答
-2

更新:我没有注意到 GROUP_CONCAT 因此您必须将子查询与 LIMIT 结合使用

使用限制

SELECT column_name(s)
FROM table_name
LIMIT number
于 2012-10-26T17:18:09.280 回答