2017-04-14 122 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. –