2017-04-27 107 views
2

好吧,当谈到SQL时,我有些不高兴。事实上非常如此,所以我很抱歉,如果这是不言而喻的。SQL:设置AVG时,上一列为空()

我试图找出从数据库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_minstotal_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 

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

+0

什么是表的架构? –

+0

@SloanThrasher - 一秒钟,会加。 – JamesG

回答

2

这是为什么?

让我们来看看AVG

AVG([DISTINCT]表达式)

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

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

和DOC在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 
+0

这对我有效。谢谢。另外,感谢您将我链接到某些内容。非常感激。 – JamesG

+0

请注意:'reply_time'对外部查询没有意义,它是来自'reply_time'嵌套表的随机值。我发布了您的答案**服务器可以自由选择每个组的任何值。**我投票直到您删除解决方案提案或您修复它。 SRR。 – danihp

+0

@danihp我删除'reply_time',这似乎是无用的。而且,你的赞同是从我这里得到的。 – Blank

1

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

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

的MySQL扩展了标准SQL使用GROUP BY的,这样的选择列表可参考在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子句中命名也未在功能上依赖于它们的非聚合列的查询。

+0

请问我能为这个外行解释你吗?我很挣扎,因为我没有使用GROUP BY ....:/ – JamesG