2013-02-27 87 views
1

任何人都可以解释为什么以下语句在MySQL中工作但在Oracle中收到“不是GROUP BY表达式”的原因吗?Oracle vs MySQL - 聚合函数

SELECT order1.user_id, 
     order1.order_datetime, 
     SUM(order2.order_total) 
    FROM order_table order1 
    JOIN order_table order2 ON order1.user_id = order2.user_id 
GROUP BY order1.user_id 

这是因为Oracle不知道如何处理order_datetime列?难道不能像它在MySQL中那样从GROUP BY order1.user_id行收到的行中返回列结果吗?

编辑:

据我所知,所有列应在group by,但我试图理解为什么Oracle没有返回类似的结果作为MySQL的(而MySQL不要求每个GROUP BY和Oracle)。

+2

因为MySQL不喜欢小猫。 – Kermit 2013-02-27 18:22:28

+4

因为MySQL认为只需选择任意'order1.order_datetime'即可。在其他严重的数据库平台中,won syntax语法是不合法的。仅仅因为MySQL对语法的松懈并不能使它正确。 – 2013-02-27 18:25:41

回答

12

Oracle实际上执行的是正确的行为。当您使用GROUP BY时,选择列表中的项目必须出现在GROUP BY或集合函数中。

SELECT order1.user_id, 
     order1.order_datetime, 
     SUM(order2.order_total) 
    FROM order_table order1 
    JOIN order_table order2 ON order1.user_id = order2.user_id 
GROUP BY order1.user_id, order1.order_datetime 

MySQL使用一个EXTENSION TO GROUP BY允许不执行该FULL GROUP BY的行为。在MySQL中使用它并不能保证order1.order_datetime的值是什么,MySQL只选择一个值,结果可能是意外的。

您需要使用GROUP BY或在SELECT列表中的所有项目上进行汇总(与上面类似),或者您必须重新编写查询。您可以使用任何如下:

SELECT order1.user_id, 
     min(order1.order_datetime) order_datetime, 
     SUM(order2.order_total) 
    FROM order_table order1 
    JOIN order_table order2 ON order1.user_id = order2.user_id 
GROUP BY order1.user_id 

,一个总量适用于order_datetime,那么你不通过之日起必须组。

您可以使用sum() over()

SELECT order1.user_id, 
     order1.order_datetime, 
     SUM(order2.order_total) over(partition by order1.user_id) order_total 
FROM order_table order1 
JOIN order_table order2 ON order1.user_id = order2.user_id 

或者这可以使用子查询重写。

SELECT order1.user_id, 
    order1.order_datetime, 
    order2.order_total 
FROM order_table order1 
JOIN 
(
    select SUM(order_total) order_total, user_id 
    from order_table 
    group by user_id 
) order2 
    ON order1.user_id = order2.user_id 
+0

bluefeet - 感谢您的详细回复。是否仍然可以使用group by来仅检索每个用户1条记录,order_total来自order2? – Mike 2013-02-27 18:19:08

+0

@Mike我提供的最终查询为您提供了每个用户的总订单。如果您不想使用子查询,并且您不想使用“按order_datetime”进行分组,则可以在该列周围使用聚合函数。 – Taryn 2013-02-27 18:22:55

+6

@Mike,您可以使用聚合函数,例如MIN(order1.order_datetime)来指示您需要第一个日期时间。不幸的是,询问项目组并不指定确定如何选择组属性的聚合是不正确的。如果你有一群男人和女人,那么询问男人的年龄和女人群的年龄是不正确的,你可能需要平均值,最小值或者最大值或者总值,但该组的“年龄”是毫无意义的。 – 2013-02-27 18:23:45

0

在oracle中则需要指定Select所有列在group by,如果你想组由只有一列,而不是所有的尝试这个

SELECT order1.user_id, 
     order1.order_datetime, 
SUM(order2.order_total) OVER (PARTITION BY order1.user_id) order_total 
    FROM order_table order1 
    JOIN order_table order2 ON order1.user_id = order2.user_id 
0

见我相关的问题here
的Mysql假定“非任何”值为非分组功能/字段,而Oracle强制需要分组功能或分组按字段

Mysql manual
MySQL extends the use of GROUP BY so that the select list can refer to nonaggregated columns not named in the GROUP BY clause. This means that the preceding query is legal in MySQL. You can use this feature to get better performance by avoiding unnecessary column sorting and grouping. However, this is useful primarily when all values in each nonaggregated column not named in the GROUP BY are the same for each group. The server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate. Furthermore, the selection of values from each group cannot be influenced by adding an ORDER BY clause. Sorting of the result set occurs after values have been chosen, and ORDER BY does not affect which values the server chooses.

+2

我不明白这是如何相关的......或者真的回答了这个问题。 – Kermit 2013-02-27 18:30:11