【问题标题】:Correct query to get average from top 5 of 7 days?正确查询以获取 7 天中前 5 天的平均值?
【发布时间】:2018-08-16 18:45:34
【问题描述】:

我正在跟踪每天的步数。我想使用 7 天期间中最好的 5 天来获得平均步数/天。我的最终目标是在总共 16 周内,在 7 天中获得最佳 5 天的平均值。

这是我的 sqlfiddle - http://sqlfiddle.com/#!9/5e69bdf/2

这是我当前使用的查询,但我发现结果不正确。它采用 7 天的平均值,而不是选择步数最多的 5 天。根据我在 sqlfiddle 中发布的数据,它平均输出 14,122,而不是 11,606。

SELECT SUM(a.steps) as StepsTotal, AVG(a.steps) AS AVGSteps
FROM (SELECT * FROM activities
      JOIN Courses
      WHERE activities.encodedid=? AND activities.activitydate BETWEEN
          DATE_ADD(Courses.Startsemester, INTERVAL $y DAY) AND 
          DATE_ADD(Courses.Startsemester, INTERVAL $x DAY) 
      ORDER BY activities.steps DESC LIMIT 5
      ) a
GROUP BY a.encodedid

这是相同的查询,其中填充了用于测试的值:

SELECT SUM(a.steps) as StepsTotal, AVG(a.steps) AS AVGSteps
FROM (SELECT * FROM activities
      JOIN Courses
      WHERE activities.encodedid='42XPC3' AND activities.activitydate BETWEEN
          DATE_ADD(Courses.Startsemester, INTERVAL 0 DAY) AND 
          DATE_ADD(Courses.Startsemester, INTERVAL 6 DAY) 
      ORDER BY activities.steps DESC LIMIT 5
      ) a
GROUP BY a.encodedid

【问题讨论】:

  • 7天期限什么时候开始?
  • 2018-07-12 - 在课程表中开始学期。
  • 在查看您的 SQL Fiddle 时,Courses 是空的。不知道为什么。我在您的架构中看不到任何错误,但 SELECT * FROM Courses 返回 0 行。
  • @SloanThrasher 我在 SQL Fiddle 中显示了 Courses 表和数据。谢谢。
  • 您得到不正确结果的一个原因是每个活动行都被计算了多次,因为它们与课程表中的多行匹配。您可以考虑只返回 Courses 表中的 DISTINCT 日期。

标签: mysql average


【解决方案1】:

正如@SloanThrasher 指出的那样,查询不起作用的原因是Courses 数据库中有同一课程的多行,这些行最终被连接到activities 数据库。因此,子查询的输出给出了最高值 (16058) 3 次加上第二高值 (11218) 两次,总共 70610 和平均 14122。您可以通过如下修改查询来解决此问题:

SELECT SUM(a.steps) as StepsTotal, AVG(a.steps) AS AVGSteps
    FROM (SELECT * FROM activities
          JOIN (SELECT DISTINCT Startsemester FROM Courses) c
          WHERE activities.encodedid='42XPC3' AND activities.activitydate BETWEEN
              DATE_ADD(c.Startsemester, INTERVAL 0 DAY) AND 
              DATE_ADD(c.Startsemester, INTERVAL 6 DAY) 
          ORDER BY CAST(activities.steps AS UNSIGNED) DESC LIMIT 5
          ) a
    GROUP BY a.encodedid

现在因为实际上只有 3 天的活动(2018-07-16、2018-07-17 和 2018-07-18)从学期开始到 6 天后(2018-07-12 和 2018- 07-18)这给出了总共37533(16058+11218+10277)和平均12517.7。

StepsTotal  AVGSteps
37553       12517.666666666666

理想情况下,您可能还想为从Courses 选择的课程添加一个约束,例如改变

(SELECT DISTINCT Startsemester FROM Courses)

(SELECT DISTINCT Startsemester FROM Courses WHERE CourseNumber='PHED1164')

【讨论】:

  • 谢谢尼克。如果我将查询更改为计算 7 - 13 天,您的查询结果是 7273.2 平均步数。但是,当我将前五天在 Excel 中取平均值时,我平均得到 10293 步。有什么想法吗?我的另一个问题是我想采纳你的建议并通过添加 CourseNumber、Semester 和 SectionNumber 来扩展它,但是当我将它们添加到查询中时,它会给出一个空白结果(SELECT DISTINCT Startsemester FROM Courses WHERE CourseNumber='PHED 1164 ' AND SectionNumber = '5075' AND Semester = 'Fall') 。 sqlfiddle.com/#!9/5e69bdf/29
  • 嗨蒂姆,SQLFiddle 目前没有回复我,我会在它回来时看看它。
  • 嗨尼克,我刚刚检查了一下,它似乎又回来了:)
  • 嗨@TimM 似乎又倒下了!你有机会在rextester 上发帖吗?
  • 嗨,蒂姆,问题是您的步骤列是 varchar 类型,而不是 int。所以它按字符串排序,'3402' > '10700'。解决方法是将步骤列转换为UNSIGNED,以便正确排序。查看我的编辑,this fiddle
【解决方案2】:

试试这个查询:

SELECT @rn := 1, @weekAndYear := 0;

SELECT weekDayAndYear,
       SUM(steps),
       AVG(steps)
FROM (
  SELECT @weekAndYear weekAndYearLag,
         CASE WHEN @weekAndYear = YEAR(activitydate) * 100 + WEEK(activitydate)
           THEN @rn := @rn + 1 ELSE @rn := 1 END rn,
         @weekAndYear := YEAR(activitydate) * 100 + WEEK(activitydate) weekDayAndYear,
         steps,
         lightly_act_min,   
         fairly_act_min,
         sed_act_min,
         vact_min,
         encodedid,
         activitydate,
         username
  FROM activities
  ORDER BY YEAR(activitydate) * 100 + WEEK(activitydate), CAST(steps AS UNSIGNED) DESC
) a WHERE rn <= 5
GROUP BY weekDayAndYear

Demo

使用附加变量,我模仿 SQL Server ROW_NUMBER 函数,从 1 到 7 天数按周划分。这样我可以过滤最好的 5 天,并轻松获得按列 weekAndDate 的平均分组,其格式与变量相同:yyyyww(我使用整数来避免转换为 varchar)。

【讨论】:

  • 谢谢米哈尔!几个问题... 1. 我希望看到 5 周的数据,即使第 5 周只有 4 天的数据,因为今天是学期末,步骤跟踪结束。 2. 将日期转换回 YYYY-MM-DD 的最佳方法是在 PHP 中还是在 MYSQL 查询中?非常感谢!!
  • @TimM 我不明白第一个问题。第二个问题:随心所欲:) 它是基于意见的,我会在 MySql 中这样做,因为我不知道 PHP。如果我的回答对您有帮助,您应该接受它(左侧的绿色复选标记)并可选择投票:)
  • 您的示例输出包含 4 周的数据。有一个第 5 周,即本周。我需要它来显示最后一周的平均步数。关于如何实现这一目标的任何建议?
  • 另一个问题。前 7 天的步数如下: 16058 11218 10277 10324 10151 3402 1730 前 5 天的平均为 11605.6。在您的演示中,它显示为 10238.3。我不知道为什么会有差异?
  • @TimM 问题是stepsvarchar - 您必须为您的列选择合适的数据类型,在MySQL 中USNIGNED 是整数数据类型,您可能需要考虑它。尝试更新的答案:)
【解决方案3】:

考虑以下几点:

 DROP TABLE IF EXISTS my_table;

CREATE TABLE `my_table` 
(id SERIAL PRIMARY KEY
,steps INT NOT NULL
);

insert into my_table (steps) values
(9),(5),(7),(7),(7),(8),(4);
select prev
    , sum(steps) total
    from (
      select steps
    , case when @prev = grp 
           then @j:=@j+1 else @j:=1 end j
    , @prev:=grp prev
    from (SELECT steps 
               , case when mod(@i,3)=0 
                      then @grp := @grp+1 else @grp:=@grp end grp -- a 3 day week
               , @i:=@i+1 i
            from my_table
               , (select @i:=0,@grp:=0) vars
           order 
              by id) x
, (select @prev:= null, @j:=0) vars
order by grp,steps desc,i) a
where j <=2 -- top 2 (out of 3)
group by prev;

+------+-------+
| prev | total |
+------+-------+
| 1    |    16 |
| 2    |    15 |
| 3    |     4 |
+------+-------+

http://sqlfiddle.com/#!9/ee46d7/11

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多