2017-04-14 80 views
0

我的表格设计用于包含宠物及其活动数据,例如睡眠时间和锻炼时间。表格定义如下。连续数天MySQL群组和聚集

CREATE TABLE IF NOT EXISTS TEST_ACTIVITY(
    pet_id INT(11) UNSIGNED NOT NULL, 
    simple_sleep_time INT(11), 
    deep_sleep_time INT(11), 
    mild_movement_time INT(11), 
    moderate_movement_time INT(11), 
    severe_movement_time INT(11), 
    start_time INT(11), 
    date DATE, 
    PRIMARY KEY (pet_id, start_time, date) 
) ENGINE=INNODB 

将以下数据插入表中。

INSERT INTO TEST_ACTIVITY (pet_id, simple_sleep_time, deep_sleep_time,mild_movement_time, moderate_movement_time, severe_movement_time, start_time, date) 
VALUES 
(100, 1, 1, 1, 1, 1, 0, '2015-03-10'), 
(100, 2, 1, 1, 1, 1, 30, '2015-03-10'), 
(100, 3, 1, 1, 1, 1, 0, '2015-03-11'), 
(100, 4, 1, 1, 1, 1, 30, '2015-03-11'), 
(100, 5, 1, 1, 1, 1, 0, '2015-03-12'), 
(100, 6, 1, 1, 1, 1, 30, '2015-03-12'), 
(100, 7, 1, 1, 1, 1, 0, '2015-03-13'), 
(100, 8, 1, 1, 1, 1, 30, '2015-03-13'), 
(101, 9, 1, 1, 1, 1, 0, '2015-03-10'), 
(101, 10, 1, 1, 1, 1, 30, '2015-03-10'), 
(101, 11, 1, 1, 1, 1, 0, '2015-03-11'), 
(101, 12, 1, 1, 1, 1, 30, '2015-03-11'), 
(101, 13, 1, 1, 1, 1, 0, '2015-03-12'), 
(101, 14, 1, 1, 1, 1, 30, '2015-03-12'), 
(101, 15, 1, 1, 1, 1, 0, '2015-03-13'), 
(101, 16, 1, 1, 1, 1, 30, '2015-03-13'), 
(102, 17, 1, 1, 1, 1, 0, '2015-03-10'), 
(102, 18, 1, 1, 1, 1, 30, '2015-03-10'), 
(102, 19, 1, 1, 1, 1, 0, '2015-03-11'), 
(102, 20, 1, 1, 1, 1, 30, '2015-03-11'), 
(102, 21, 1, 1, 1, 1, 0, '2015-03-12'), 
(102, 22, 1, 1, 1, 1, 30, '2015-03-12'), 
(102, 23, 1, 1, 1, 1, 0, '2015-03-13'), 
(102, 24, 1, 1, 1, 1, 30, '2015-03-13'); 

select * from TEST_ACTIVITY ORDER BY pet_id, date, start_time; 

+--------+-------------------+-----------------+--------------------+------------------------+----------------------+------------+------------+ 
| pet_id | simple_sleep_time | deep_sleep_time | mild_movement_time | moderate_movement_time | severe_movement_time | start_time | date  | 
+--------+-------------------+-----------------+--------------------+------------------------+----------------------+------------+------------+ 
| 100 |     1 |    1 |     1 |      1 |     1 |   0 | 2015-03-10 | 
| 100 |     2 |    1 |     1 |      1 |     1 |   30 | 2015-03-10 | 
| 100 |     3 |    1 |     1 |      1 |     1 |   0 | 2015-03-11 | 
| 100 |     4 |    1 |     1 |      1 |     1 |   30 | 2015-03-11 | 
| 100 |     5 |    1 |     1 |      1 |     1 |   0 | 2015-03-12 | 
| 100 |     6 |    1 |     1 |      1 |     1 |   30 | 2015-03-12 | 
| 100 |     7 |    1 |     1 |      1 |     1 |   0 | 2015-03-13 | 
| 100 |     8 |    1 |     1 |      1 |     1 |   30 | 2015-03-13 | 
| 101 |     9 |    1 |     1 |      1 |     1 |   0 | 2015-03-10 | 
| 101 |    10 |    1 |     1 |      1 |     1 |   30 | 2015-03-10 | 
| 101 |    11 |    1 |     1 |      1 |     1 |   0 | 2015-03-11 | 
| 101 |    12 |    1 |     1 |      1 |     1 |   30 | 2015-03-11 | 
| 101 |    13 |    1 |     1 |      1 |     1 |   0 | 2015-03-12 | 
| 101 |    14 |    1 |     1 |      1 |     1 |   30 | 2015-03-12 | 
| 101 |    15 |    1 |     1 |      1 |     1 |   0 | 2015-03-13 | 
| 101 |    16 |    1 |     1 |      1 |     1 |   30 | 2015-03-13 | 
| 102 |    17 |    1 |     1 |      1 |     1 |   0 | 2015-03-10 | 
| 102 |    18 |    1 |     1 |      1 |     1 |   30 | 2015-03-10 | 
| 102 |    19 |    1 |     1 |      1 |     1 |   0 | 2015-03-11 | 
| 102 |    20 |    1 |     1 |      1 |     1 |   30 | 2015-03-11 | 
| 102 |    21 |    1 |     1 |      1 |     1 |   0 | 2015-03-12 | 
| 102 |    22 |    1 |     1 |      1 |     1 |   30 | 2015-03-12 | 
| 102 |    23 |    1 |     1 |      1 |     1 |   0 | 2015-03-13 | 
| 102 |    24 |    1 |     1 |      1 |     1 |   30 | 2015-03-13 | 
+--------+-------------------+-----------------+--------------------+------------------------+----------------------+------------+------------+  

我想用这个公式先计算每个宠物的日分数:score = SUM(severe_movement_time) + SUM(moderate_movement_time) + SUM(mild_movement_time) + SUM(simple_sleep_time),然后再决定根据其得分每个宠物的等级。通过使用以下查询,我可以在2015-03-10的一天内完成。

SELECT pet_id, date, score, rank 
FROM 
(
SELECT t.pet_id, t.date, t.score, @prev := @curr, @curr := score, @rank := IF(@prev = @curr, @rank, @rank+1) AS rank 
FROM (
    SELECT pet_id, date, COALESCE(SUM(simple_sleep_time), 0) shallow, 
      COALESCE(SUM(deep_sleep_time), 0) deep, COALESCE(SUM(mild_movement_time), 0) light, 
      COALESCE(SUM(moderate_movement_time), 0) moderate, COALESCE(SUM(severe_movement_time), 0) heavy, 
      (COALESCE(SUM(severe_movement_time), 0) + COALESCE(SUM(moderate_movement_time), 0) + COALESCE(SUM(mild_movement_time), 0) + COALESCE(SUM(simple_sleep_time), 0)) score 
    FROM TEST_ACTIVITY 
    WHERE date = DATE('2015-03-10') 
    GROUP BY pet_id 
    ORDER BY score DESC 
) t, (SELECT @curr := null, @prev := null, @rank := 0) r ORDER BY score DESC 
) x 

我的问题是如何编写一个查询来计算分数和排名连续数天,例如4天(起始= 2015年3月10日日期,结束日期= 2015年3月13日)。预期结果如下所示。

| pet_id | date  | score | rank | 
+--------+------------+-------+------+ 
| 102 | 2015-03-10 | 41 | 1 | 
| 101 | 2015-03-10 | 25 | 2 | 
| 100 | 2015-03-10 | 9  | 3 | 
| 102 | 2015-03-11 | 45 | 1 | 
| 101 | 2015-03-11 | 29 | 2 | 
| 100 | 2015-03-11 | 13 | 3 | 
| 102 | 2015-03-12 | 49 | 1 | 
| 101 | 2015-03-12 | 33 | 2 | 
| 100 | 2015-03-12 | 17 | 3 | 
| 102 | 2015-03-13 | 53 | 1 | 
| 101 | 2015-03-13 | 37 | 2 | 
| 100 | 2015-03-13 | 21 | 3 | 
+1

认真考虑修改您的设计 – Strawberry

+0

只是按GROUP BY pet_id组织,日期 – Cherif

回答

1

请尝试以下...

SELECT pet_id, 
     date, 
     score, 
     rank 
FROM 
(
    SELECT pet_id, 
      date, 
      score, 
      @prevDate := COALESCE(@currDate, 
            CURDATE()) as prevDate, 
      @currDate := date, 
      @prevScore := COALESCE(@currScore, 
            -1) AS prevScore, 
      @currScore := score, 
      @rank := IF(@prevDate <> @currDate, 
         1, 
         IF(@prevScore = @currScore, 
          @rank, 
          @rank + 1)) AS rank 
    FROM 
    (
     SELECT pet_id, 
       date, 
       (COALESCE(SUM(severe_movement_time), 
          0) + 
        COALESCE(SUM(moderate_movement_time), 
           0) + 
        COALESCE(SUM(mild_movement_time), 
           0) + 
        COALESCE(SUM(simple_sleep_time), 
           0)) AS score 
     FROM TEST_ACTIVITY 
     WHERE date BETWEEN DATE('2015-03-10') AND DATE('2015-03-13') 
     GROUP BY pet_id, 
       date 
    ) AS scoreFinder, (SELECT @currDate := NULL, 
           @prevDate := NULL, 
           @currScore := NULL, 
           @prevScore := NULL, 
           @rank := 0) AS r 
    ORDER BY date, 
      score DESC 
) AS rankFinder; 

我根据我对你给我们的代码答案。我的第一个修改是删除shallow,deep等的计算结果,因为它们在计算后从不再被引用。

我的下一个修改是将最内层查询的WHERE子句更改为使用BETWEEN运算符来定义记录必须来自的日期范围。我已经使用了问题中的显式值,但您当然可以使用其他值或保存这些值的变量。

由于我们感兴趣的是每个pet_idscore每个date,我扩展了这个列表分组子句GROUP BYpet_iddate配对。

由于此时不需要对列表进行排序,我删除了ORDER BY子句。

我不喜欢ultrashort别名,因为越复杂的语句越容易失去跟踪代码和出错,无论是在编码或调试时,这就是为什么我将t更改为scoreFinder(我尝试使用short但是描述性别名)。你当然可以自由地将它称为任何你喜欢的东西。

此列表与valuesInitialiser一起构成最中间查询的基础,该查询从date开始订购此基数,并在分数上进行子分类。

对于排序列表,现在可以开始计算rank。由于记录的rank取决于它的date和它的score与前一记录的相比,因此必须跟踪每个记录的当前值和以前的值。作为排序中更主要的字段,需要首先比较date的值。如果它们不同,则正在检查新的date的第一条记录,这意味着rank的值将需要(重新)初始化为1。如果两个日期相同,则需要测试score中的更改。如果得分没有改变,则需要使用rank的当前值。否则,需要递增rank的当前值并使用新值。

随着生成rank的值,剩下的只是选择所需的字段。

为了测试这个声明,我将它与您提供的数据进行了对比,这些数据产生了期望的结果。然而,我注意到,从样本数据score小号都是不同的,所以我改变的一个记录从(101, 12, 1, 1, 1, 1, 30, '2015-03-11')(101, 12, 1, 1, 1, 17, 30, '2015-03-11')使得scorepet_iddate匹配,对于pet_id = 102date。我比重新测试了我的陈述,因为我希望pet_id的排名相同。

如果您有任何问题或意见,请随时发布相应评论。

+0

按Enter或复制一个新行字符往往会在这一点完成一个评论。 – toonice

+0

你是否希望根据'date'排序的rresults和'score'进行子分类,然后呢? – toonice

+0

嗨toonice,排名不正确。例如,当pet_id = 100,日期= 2015-03-10,分数= 9时,rank等于2(应该是3)。宠物的等级基于其日常分数。例如,在日期= 2015-03-10,pet_id = 102具有最高分41,其等级为1. –