3

問題: カテゴリごとに、1 つのカテゴリに少なくとも 10 個のアイテムを持っている最初の 2 人のユーザーを見つけます。

テーブル構造:

CREATE TABLE items(
    id INT AUTO_INCREMENT PRIMARY KEY,
    datetime datetime,
    category INT,
    user INT,
    items_count INT
);

 

サンプルデータ:

INSERT INTO items (datetime, category, user, items_count) VALUES
('2013-01-01 00:00:00', 1, 1, 10),
('2013-01-01 00:00:01', 1, 2, 1),
('2013-01-01 00:00:02', 1, 3, 10),
('2013-01-01 00:00:03', 1, 2, 9),

('2013-01-01 00:00:00', 2, 4, 10),
('2013-01-01 00:00:01', 2, 1, 10),
('2013-01-01 00:00:01', 2, 5, 10);

 

望ましい結果:

category    user
1           1
1           3
2           4
2           5

 

注: 結果に示されているように、複数のユーザーが同時に要件を満たしている場合に、ユーザーに対して好みを示すことができる必要があります。

 

SQL フィドル:

http://sqlfiddle.com/#!2/58e60

 

これは私が試したことです:

SELECT
  Derived.*,
  IF (@category != Derived.category, @rank := 1, @rank := @rank + 1) AS rank,
  @category := category


FROM(
  SELECT
    category,
    user,
    SUM(items_count) AS items_count,
    MAX(datetime) AS datetime


  FROM items


  GROUP BY
    category,
    user

  HAVING
    SUM(items_count) >= 10
) AS Derived


JOIN(SELECT @rank := 0, @category := 0) AS r


HAVING
  rank <= 2

ORDER BY
  Derived.category,
  Derived.datetime

 

しかし、それは欠陥があります。ユーザーの優先順位が考慮されないだけでなく、次のようなデータで間違った結果が生成されます。

('2013-01-01 00:00:00', 1, 1, 10),
('2013-01-01 00:00:01', 1, 2, 1),
('2013-01-01 00:00:02', 1, 3, 10),
('2013-01-01 00:00:03', 1, 2, 9),
('2013-01-01 00:00:10', 1, 3, 1);

 

追加情報: このシナリオで手順が違いを生むかどうかはわかりませんが、残念ながらそれも選択肢ではありません。このクエリを実行するユーザーには、SELECT 権限しかありません。

4

2 に答える 2

0

Gordon のクエリを試してみましたが、残念ながら大きなテーブルではうまくいかないようです。結果を15分待った後、私はそれを殺すことにしました。ただし、次のクエリは非常にうまく機能し、約 8 秒で最大 6M 行のテーブルを処理しました。

    #Variable
SET @min_items      = 10,
    @max_users      = 2,
    @preferred_user = 5,

    #Static
    @category       = 0,
    @user           = 0,
    @items          = 0,
    @row_num        = 1;


--


SELECT
  category,
  user,
  datetime


FROM(
  SELECT
    category,
    user,
    datetime,
    IF (@category = category, @row_num := @row_num + 1, @row_num := 1) AS row_num,
    @category := category


  FROM(
    SELECT
      category,
      user,
      datetime,
      IF (@user != user, @items := 0, NULL),
      IF (@items < @min_items, @items := @items + items_count, NULL) AS items_cumulative,
      @user := user


    FROM items


    ORDER BY
      category,
      user,
      datetime
  ) AS Derived


  WHERE items_cumulative >= @min_items


  ORDER BY
    category,
    datetime,
    FIELD(user, @preferred_user, user)
) AS Derived


WHERE row_num <= @max_users;
于 2013-07-23T13:07:38.813 に答える