2017-04-14 2 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の1日を実行できます。

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日(START_DATE = 2015年3月10日、END_DATE = 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演算子を使用して、レコードを取得する必要があると考えられる日付範囲を定義するように変更しました。あなたの質問の明示的な値を使用しましたが、もちろんこれらの値を保持する他の値や変数を使用することもできます。

私たちは、各dateための各pet_idscoreに興味があるので、私はGROUP BYpet_iddateのペアリングに句をグループ化し、このリストを拡大しました。

この時点で一覧の並べ替えが必要ないため、ORDER BY句を削除しました。

私は非常に複雑なステートメントほど嫌ですが、コーディングやデバッグの際に、表現しているものを見失ってミスを犯すのが簡単であるため、tscoreFinderに変更しました記述的なエイリアス)。もちろん、あなたが好きなものを自由に呼ぶことができます。

このリストはvaluesInitialiserと結合されています。これは、このベースをdateで順序付けし、スコアでサブソートすることから始まります。

ソートリストを利用できるようになり、rankの計算が開始されます。レコードのrankは、前のレコードと比較してdateとそのscoreの両方に依存するため、それぞれの現在値と前の値を追跡する必要があります。ソートのより支配的なフィールドとして、dateの値を最初に比較する必要があります。それらが異なる場合は、新しいdateの最初のレコードが調べられています。つまり、rankの値は1に初期化する必要があります。 2つの日付が同じ場合は、scoreの変更をテストする必要があります。スコアが変更されていない場合は、rankの現在の値を使用する必要があります。それ以外の場合は、現在の値rankをインクリメントし、新しい値を使用する必要があります。

rankという値が生成された場合、残っているのはすべて、必要なフィールドだけを選択することだけです。

このステートメントをテストするために、私はあなたの提供したデータと比較して実行しました。これは望ましい結果をもたらしました。しかし、そのためpet_idためscoreとそのdateが一致したことを私はサンプルデータからscore sがすべて異なっていたことに気づいたので、私は(101, 12, 1, 1, 1, 17, 30, '2015-03-11')(101, 12, 1, 1, 1, 1, 30, '2015-03-11')からレコードの1つを変更していることdateためpet_id = 102ため。私はpet_idの両方で同じランクを生み出したと期待していた私の声明を再テストした。

ご不明な点がございましたら、お気軽にコメントを投稿してください。

+0

Enterを押すか、改行文字でコピーすると、その時点でコメントが完成する傾向があります。 – toonice

+0

結果を 'date'でソートし、' score'で小ソートしたいのですか? – toonice

+0

こんにちは、toonice、ランキングが間違っています。たとえば、pet_id = 100、date = 2015-03-10、score = 9の場合、rankは2になります(3にする必要があります)。ペットのランクは、その日のスコアに基づいています。たとえば、date = 2015-03-10の場合、pet_id = 102のスコアは41、ランクは1です。 –

関連する問題