我的桌子旨在包含宠物及其活动数据,例如睡眠时间和锻炼时间。表定义如下。
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天(start_date = 2015-03-10,end_date = 2015-03-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 |
答案 0 :(得分: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_id
的每个score
date
感兴趣,因此我将此列表分组条款扩展为GROUP BY
pet_id
和{{1配对。
由于此时不需要对列表进行排序,因此我删除了date
子句。
我不喜欢超短别名,因为更复杂的声明越容易丢失它们所代表的内容并犯错误,无论是在编码还是调试时,这就是我将ORDER BY
更改为t
的原因(我尝试使用简短但描述性的别名)。无论你喜欢什么,你都可以自由地称呼它。
与scoreFinder
结合的此列表构成了最中间查询的基础,该查询首先按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' )
为{ {1}} score
与pet_id
的{{1}}匹配date
。我重复测试了我的陈述,希望对pet_id = 102
的两个等级产生相同的等级。
如果您有任何问题或意见,请随时发表评论。