SQL:设置AVG()

时间:2017-04-27 07:49:33

标签: mysql sql

好的,就SQL来说,我是一个小小的noobie。事实上非常如此,所以如果这是不言自明的,我道歉。

我试图从数据库中找出3件事(这张表是发送的每条消息的日志):

  • 总回复时间
  • 不到10分钟的回复总数
  • 平均回复时间

这是我的SQL:

        SELECT
           *, SUM(case when tmp.reply_time <= 10 then 1 else 0 end) as under_10_mins,
           COUNT(tmp.reply_time) AS total_replies
        FROM
           (SELECT 
              TIMESTAMPDIFF(MINUTE, `date`, reply_date) as reply_time
           FROM
               tme_email_staff_reply sr
           JOIN 
               tme_user u 
           ON 
               u.id = sr.staff_id
           JOIN
               tme_email_message m 
           ON           
               m.id = sr.message_id
                   WHERE
               `reply_date` >= '2017-04-01 00:00:00'
           AND 
               `reply_date` < '2017-04-27 00:00:00'
           ) 
        AS tmp

哪个输出:

    | reply_time | under_10_mins | total_replies |
    |        106 |           165 |           375 |

现在,当我加入时:

        SELECT
           *, SUM(case when tmp.reply_time <= 10 then 1 else 0 end) as under_10_mins,
           COUNT(tmp.reply_time) AS total_replies
        FROM
           (SELECT 
              TIMESTAMPDIFF(MINUTE, `date`, reply_date) as reply_time,
              (AVG(TIMESTAMPDIFF(SECOND, `date`, reply_date))/60) AS average_reply_time
           FROM
               tme_email_staff_reply sr
           JOIN 
               tme_user u 
           ON 
               u.id = sr.staff_id
           JOIN
               tme_email_message m 
           ON           
               m.id = sr.message_id
                   WHERE
               `reply_date` >= '2017-04-01 00:00:00'
           AND 
               `reply_date` < '2017-04-27 00:00:00'
           ) 
        AS tmp

我的回答是:

    | reply_time | average_reply_time |under_10_mins | total_replies |
    |        106 |       149.08626667 |            0 |             1 |

如您所见, under_10_mins total_replies 字段已更改。

链接表的架构:

tme_email_staff_reply:

    id |    staff_id |   message_id |            reply_date |
     1 | 234,221,001 | 15fg16d5dgw2 |   2017-04-01 09:34:16 | 

tme_user

    id |    username |   password |    email |   dob |   gender | 
    // data omited

tme_email_message

   id | thread_id    | From | To | subject | message |  message_id
   // data omited

谁能告诉我为什么会这样?以及如何解决它?

2 个答案:

答案 0 :(得分:2)

为什么会这样?

让我们看看AVG

  

AVG([DISTINCT] expr)

     

返回expr的平均值。 DISTINCT选项可用于返回expr的不同值的平均值。

     

如果没有匹配的行,AVG()将返回NULL。

13.19.1 Aggregate (GROUP BY) Function Descriptions中的文档也说:

  

如果在不包含GROUP BY子句的语句中使用组函数,则它等同于对所有行进行分组。有关详细信息,请参阅Section 13.19.3, “MySQL Handling of GROUP BY”

这意味着在您的子查询中,您使用了avg而没有group by,这将avg所有行,然后在子查询中返回一行。

如何解决?

我认为你应该将avg从子查询移到外部查询:

SELECT
   SUM(case when tmp.reply_time <= 10 then 1 else 0 end) as under_10_mins,
   COUNT(tmp.reply_time) AS total_replies,
   AVG(average_reply_time) AS average_reply_time
FROM
   (SELECT 
      TIMESTAMPDIFF(MINUTE, `date`, reply_date) as reply_time,
      (TIMESTAMPDIFF(SECOND, `date`, reply_date))/60 AS average_reply_time
   FROM
       tme_email_staff_reply sr
   JOIN 
       tme_user u 
   ON 
       u.id = sr.staff_id
   JOIN
       tme_email_message m 
   ON           
       m.id = sr.message_id
           WHERE
       `reply_date` >= '2017-04-01 00:00:00'
   AND 
       `reply_date` < '2017-04-27 00:00:00'
   ) 
AS tmp

答案 1 :(得分:1)

问题是因为,在嵌套查询中,您指的是5.7.5下MySQL版本的GROUP BY子句中未命名的非聚合列。请参阅文档,注意: The server is free to choose any value from each group

MySQL < 5.7.5允许这种语法,但有特殊行为(你的情况):

  

MySQL扩展了GROUP BY的标准SQL使用,以便选择列表可以引用GROUP BY子句中未命名的非聚合列。您可以通过避免不必要的列排序和分组来使用此功能获得更好的性能。但是,当GROUP BY中未命名的每个非聚合列中的所有值对于每个组都相同时,这非常有用。服务器可以自由选择每个组中的任何值,因此除非它们相同,否则所选的值是不确定的。此外,添加ORDER BY子句不会影响每个组中值的选择。选择值后会发生结果集排序,ORDER BY不会影响服务器选择的每个组中的值。

MySQL >= 5.7.5允许这种语法并检查功能依赖性:

  

MySQL 5.7.5及更高版本实现了对功能依赖的检测。如果启用了ONLY_FULL_GROUP_BY SQL模式(默认情况下是这样),MySQL拒绝查询,其中选择列表,HAVING条件或ORDER BY列表引用既未在GROUP BY子句中命名也未在功能上依赖于它们的非聚合列。