2016-01-06 153 views
0

我正在学习MySQL,并在网站上练习练习题(未命名,但它是问题81)。问题在于GROUP BY之后的字段序列。我确定GROUP BY之后的字段序列会影响查询结果,这些结果基于报告中隐藏表的预期行数和实际行数之间的比较结果。我对这个网站和其他人的大量阅读理解是没有关系的。GROUP BY字段的序列影响MySQL查询结果

的任务是:

From Outcome table, retrieve all rows for that month (months) 
in view of a year, in which total value of expenses (out) is maximal. 

表描述是:

Outcome(code, point, date, out) where code is the primary key, 
point is a simple integer, date is in the format datetime, and out is a currency value. 

这里是我的查询:

SELECT code,point,date,`out` outc FROM outcome 
    WHERE EXTRACT(MONTH FROM date) = 
     (SELECT mon bestmonth FROM 
      (SELECT MAX(sout), mon,yr FROM 
       (SELECT SUM(outc) sout,mon,yr FROM 
        (SELECT EXTRACT(MONTH FROM date) mon, `out` outc, 
         date,EXTRACT(YEAR FROM date) yr FROM outcome 
        ) maxmonth GROUP BY mon,yr 
       ) peak 
      ) tmonth 
     ) 
    AND EXTRACT(YEAR FROM date) = 
     (SELECT yr bestyear FROM 
      (SELECT MAX(yout), mon,yr FROM 
       (SELECT SUM(outy) yout,mon,yr FROM 
        (SELECT EXTRACT(MONTH FROM date) mon, `out` outy, 
         date,EXTRACT(YEAR FROM date) yr FROM outcome 
        ) maxyear GROUP BY yr,mon 
       ) peakb 
      ) tyear 
     ) 

虽然不是一个优雅的查询,我想明白为什么在maxmonth和maxyear子查询中将顺序从“GROUP BY mon,yr”更改为“GROUP BY yr,mon”会有任何影响。

在maxmonth子查询, 'GROUP BY星期一,年' 的结果:

Wrong Your query produced correct result set on main database, 
but it failed test on second, checking database 
* Wrong number of records (less by 6) 

出于同样的maxmonth子查询, 'GROUP BY年,星期一' 的结果:

Wrong Your query produced correct result set on main database, 
but it failed test on second, checking database 
* Wrong number of records (less by 11) 
+0

这是一个疯狂的查询。这是对原始问题81的翻译吗? – Strawberry

回答

0

你需要了解该组由1列并不意味着所有其他列将具有分组的价值..

例如,给定的表:

customer | value | date 
     1 | 2 | 2015-01-03 
     1 | 3 | 2015-01-05 
     2 | 3 | 2015-01-02 
     2 | 4 | 2015-01-03 
     2 | 5 | 2015-01-04 

如果使用

select customer, max(value), date from table group by customer 

你的结果可能是

customer | max(value) | date 
     1 |  3  | 2015-01-03 
     2 |  5  | 2015-01-02 

它不是你想要的......因为agregation功能仅适用于该列。

它coud帮助:

select year(date) yr, month(date) mon, sum(outc) totalOfMonth from outcome group by yr, mon order by totalOfMonth 
0

GROUP BY目前影响结果的顺序返回(虽然MySQL已经警告说,这种行为在将来可能会改变,所以不依赖于它)。由于包含这些GROUP BY查询的查询暗含GROUP BY子句不包含非聚合字段,因此为这些字段选择要返回的值在官方上是不确定的。

(它通常是遇到的第一个或最后一个值,我避免这样的查询,因为它们的不可预测性)。

编辑/供参考:大多数其他RDBMS甚至不允许使用不包含所有非聚合字段的GROUP BY子句的查询。MySQL甚至允许它遭到批评;尽管这是我的假设原始意图(和更新版本的服务器设置似乎证实了这一点)是为了允许更简洁的查询,其中查询作者KNOWS将只有一组值的非聚合字段每个GROUPed集值;例如通过一个表上的主键进行分组,而不包括来自连接表的字段可能会有所不同(例如:只有非聚合的非分组字段来自其PK是分组标准的一部分的表)。

+0

我想我明白你在说什么。为了解决这个问题,我删除了MAX并使用了一个新的子查询。不幸的是,在网站上测试的查询会导致运行时错误。这(由于评论限制发布在下面)是一个很好的解决方法吗?感谢您的回应。 –

+0

@matman_mo在哪里? – Uueerdo

0

基本上,我从答案的解释是在使用GROUP BY时总是使用所有相关的非聚合字段。如果表格中包含其他字段,则可能有问题,在这种情况下,MAX值可能不是真正的MAX值,可能是任意的。最初的查询在结果表(maxmonth派生表)上包含GROUP BY,该表没有包含所有非聚合字段,并且GROUP BY的结果值得怀疑。

从作为我明白的答案的要点是:

1)具有用于表应该报告对应于包含在GROUP BY子句的域值的实际MAX值的聚集体如MAX值的查询(客户),但未包含在GROUP BY中的字段(如日期)不一定对应于正确的MAX值。从上面的第一个答案可以明显看出,客户和MAX值是正确的,但日期(不包含在GROUP BY中)可能实际上并不对应于客户/ MAX值行。使用仅具有相关非聚合值(月和年)的派生表(formattedOutMonthYear_sq表)并创建新派生表(groupedOutMonthYear_sq表)来执行聚合SUM应该会导致月和年的正确值,尽管代码和点如果使用了结果表而不是formattedOutMonthYear表,那么字段可能不是。

2)使用诸如MAX(峰值表)之类的聚合而未明确包含任何GROUP BY的非聚合字段可能会导致意外的结果。在原始代码中,派生表上包含非聚合的派生表上的聚合MAX可能仍会由于隐式分组而聚集在一起。

GROUP BY仍然包含多个列,但我从上述答案中得出的解释是,如果包含所有非聚合列(Uueerdo)并且不从查询(Renan)中推断附加字段,则可接受多个列。

不幸的是,运行查询会导致运行时错误,这是不幸的。感谢您解释我观察到的结果,并将该逻辑合并到查询写作中。

SELECT o.code cd,o.point pnt ,o.date dt,`out` expense,mdt FROM outcome o 
JOIN 
(SELECT EXTRACT(MONTH FROM date) mdt, EXTRACT(YEAR FROM date) ydt, code FROM outcome 
) mnth 
ON mnth.code = o.code 
WHERE mdt = 
    (
    SELECT distinct mon topMonth from 
     (SELECT SUM(outm) allOutMonth, mon, yr FROM 
      (SELECT EXTRACT(MONTH FROM date) mon, `out` outm, EXTRACT(YEAR FROM date) yr 
      FROM outcome 
      ) formattedOutMonthYear_sq GROUP BY yr, mon 
     ) topMonth_sq 
     WHERE topMonth_sq.allOutMonth >= all 
     (SELECT allOutMonth from 
      (SELECT SUM(outm) allOutMonth, mon, yr FROM 
       (SELECT EXTRACT(MONTH FROM date) mon, `out` outm, 
        EXTRACT(YEAR FROM date) yr 
       FROM outcome 
       ) formattedOutMonthYear_sq GROUP BY yr, mon 
      ) groupedOutMonthYear_sq 
     ) 
    )   
AND ydt = 
    (
    SELECT yr topTopYear from 
     (SELECT SUM(outm) allOutYear, mon, yr FROM 
      (SELECT EXTRACT(MONTH FROM date) mon, `out` outm, 
       EXTRACT(YEAR FROM date) yr 
      FROM outcome 
      ) formattedOutYearMonth_sq GROUP BY yr, mon 
     ) topYear_sq 
     WHERE topYear_sq.allOutYear >= all 
     (SELECT allOutYear from 
      (SELECT SUM(outm) allOutYear, mon, yr FROM 
       (SELECT EXTRACT(MONTH FROM date) mon, 
        `out` outm, EXTRACT(YEAR FROM date) yr 
       FROM outcome 
       ) formattedOutMonthYear_sq GROUP BY yr, mon 
      ) groupedOutYearMonth_sq 
     ) 
    )