2013-07-19 86 views
3

问题:查找每个类别中至少有10个项目的前2个用户。每组,找到头数为N的用户,使用SUM(x)> = N

表结构:

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权限。

+0

该帖子的演示文稿似乎只是尖叫作业;和你很像[tag:mysql],我想知道是否应用功课。就这样。 –

+0

为什么user_id 2不可见,它似乎在类别1中有10个项目 – Akash

+0

@BradChristie:[家庭作业标记已被弃用。](http://meta.stackexchange.com/q/147100/161666) –

回答

0

我尝试了戈登的查询,但不幸的是它似乎不适用于大型表格;等待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; 
2

为了找到满足您需求的用户,您需要累计计数总和。以下查询查找用户首次达到10个单位的时机。如果计数是从来没有否定,那么就只有一个:

select i.* 
from (select i.*, 
      (select sum(items_count) 
       from items i2 
       where i2.user = i.user and 
        i2.category = i.category and 
        i2.datetime <= i.datetime 
      ) as cumsum 
     from items i 
    ) i 
where cumsum - items_count < 10 and cumsum >= 10 
order by datetime; 

为了得到前两个,你需要使用MySQL的技巧组内计数。下面是一般工作的例子:

select i.* 
from (select i.*, if(@prevc = category, @rn := @rn + 1, @rn := 1) as rn, @prevc := category 
     from (select i.*, 
        (select sum(items_count) 
        from items i2 
        where i2.user = i.user and 
          i2.category = i.category and 
          i2.datetime <= i.datetime 
        ) as cumsum 
      from items i 
      ) i 
      cross join 
      (select @rn := 0) const 
     where cumsum - items_count < 10 and cumsum >= 10 
    ) i 
where rn <= 2 
order by category, datetime; 

我有这种方法的一个问题,因为没有在MySQL中说,表达@prevc := category实际上计算为rn后计算。但是,似乎是这样,这似乎在实践中起作用。

相关问题