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

したがって、これにより、すべてのユーザーの現在のすべてのアイテムが返されますが、これまでのところ問題ありません。しかし、最新の 10 個のアイテムだけが必要です。ヘルプに追加ORDER BYGROUP_CONCATますが、それでも最後の 10 レコードは表示されません。

編集

このようなことをしてハードコーディングするとuser_id、その1人のユーザーに必要な結果を得ることができます.問題はそれを組み合わせて、ハードコーディングする必要がなく、たとえば、すべてのユーザーの最後の10項目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、同じユーザーに対して同じ行が2つないことを前提としています。

タイムスタンプ フィールドが常に正の整数である場合は、 を に置き換えることもできNOT EXISTS...ORますCOALESCE

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 と組み合わせてサブクエリを使用する必要があります

LIMITを使用

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