完全理解GROUP BY时遇到问题

时间:2012-10-23 00:32:16

标签: sql oracle

我正在为一个考试做一些练习题,我已经出现了,我有一个完全理解小组的问题。我看到 GROUP BY 如下:将结果集分组为一列或多列。

我有以下数据库架构

enter image description here

enter image description here

我的查询

SELECT orders.customer_numb, sum(order_lines.cost_line), customers.customer_first_name, customers.customer_last_name
FROM orders
INNER JOIN customers ON customers.customer_numb = orders.customer_numb
INNER JOIN order_lines ON order_lines.order_numb = orders.order_numb
GROUP BY orders.customer_numb, order_lines.cost_line, customers.customer_first_name,     customers.customer_last_name
ORDER BY order_lines.cost_line DESC

我正在努力理解
为什么我不能只使用GROUP BY orders.cost_line并按cost_line对数据进行分组?

我想要实现的目标
我想获得花费最多钱的客户的名字。我只是不完全明白如何实现这一目标。我理解联接是如何工作的,我似乎无法理解为什么我不能简单地使用GROUP BY customer_numb和cost_line(用sum()来计算花费的金额)。我似乎总是得到“不是GROUP BY表达”,如果有人可以解释我做错了什么(不只是给我答案),这将是伟大的 - 我真的很感激,当然任何资源,你必须正确使用GROUP。

对于这篇漫长的文章感到抱歉,如果我错过了任何我道歉的话。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:6)

  

我似乎无法理解为什么我不能简单地使用GROUP BY   customer_numb和cost_line(sum()用于计算金额   略去)。

当您说group by customer_numb时,您知道customer_numb唯一标识了customer表中的一行(假设customer_numb是主键或备用键),因此任何给定的customers.customer_numb都只有一行customers.customer_first_name customers.customer_last_namecustomer_numb的值。但是在解析时Oracle不知道,或者至少表现得像它不知道那样。它有点恐慌地说:“如果一个customer_first_nameselect的多个值,该怎么办?”

规则大致是,group by子句中的表达式可以使用customer_first_name || customer_last_name子句中的表达式和/或使用聚合函数。 (以及不依赖于基表的常量和系统变量等)和“使用”我的意思是表达式或表达式的一部分。因此,一旦您对名字和姓氏进行分组,customers也将是一个有效的表达式。

当您有一个表,如group by并按主键分组,或者具有唯一键而非空约束的列时,您可以安全地将它们包含在group by customer.customer_numb, customer.customer_first_name, customer.customer_last_name.子句中。在此特定情况下,order by

另请注意,第一个查询中的order_lines.cost_line将失败,因为sum(order_lines.cost_line)没有该组的单个值。您可以在select上订购或在alias子句中使用列别名,并在SELECT orders.customer_numb, sum(order_lines.cost_line), customers.customer_first_name, customers.customer_last_name FROM orders INNER JOIN customers ON customers.customer_numb = orders.customer_numb INNER JOIN order_lines ON order_lines.order_numb = orders.order_numb GROUP BY orders.customer_numb, customers.customer_first_name, customers.customer_last_name ORDER BY sum(order_lines.cost_line) 上订购

SELECT orders.customer_numb, 
    sum(order_lines.cost_line) as sum_cost_line, 
. . .
ORDER BY sum_cost_line

customer_numb

注意:我听说有些RDBMS会暗示分组的其他表达式而不明确说明。 Oracle不是那些RDBMS之一。

至于cost_lineCustomer Number | Cost Line 1 | 20.00 1 | 20.00 2 | 35.00 2 | 30.00 select customer_number, cost_line, sum(cost_line) FROM ... group by customer_number, cost_line order by sum(cost_line) desc Customer Number | Cost Line | sum(cost_line) 1 | 20.00 | 40.00 2 | 35.00 | 35.00 2 | 30.00 | 30.00 的分组考虑一个有两个客户的数据库,1和2,每个客户有两个订单:

sum(cost_line)

最高{{1}}的第一行不是花费最多的客户。

答案 1 :(得分:3)

  

我理解联合是如何工作的,我似乎无法理解   为什么我不能简单地使用GROUP BY customer_numb和cost_line(使用sum())   用于计算花费的金额。)

这应该为您提供每个客户的总和。

SELECT orders.customer_numb, sum(order_lines.cost_line)
FROM orders
INNER JOIN order_lines ON order_lines.order_numb = orders.order_numb
GROUP BY orders.customer_numb

请注意,SELECT子句中聚合函数的参数的每一列也是GROUP BY子句中的一列。

现在您可以将其与其他表连接以获取更多详细信息。这是使用公用表表达式的一种方法。 (还有其他方式来表达你想要的东西。)

with customer_sums as (
    -- We give the columns useful aliases here.
    SELECT orders.customer_numb as customer_numb, 
           sum(order_lines.cost_line) as total_orders
    FROM orders
    INNER JOIN order_lines ON order_lines.order_numb = orders.order_numb
    GROUP BY orders.customer_numb
)
select c.customer_numb, c.customer_first_name, c.customer_last_name, cs.total_orders
from customers c
inner join customer_sums cs
on cs.customer_numb = c.customer_numb
order by cs.total_orders desc
  

为什么我不能简单地使用GROUP BY orders.cost_line并将其分组   cost_line数据?

将GROUP BY应用于order_lines.cost_line将为order_lines.cost_line中的每个不同值提供一行。 (列orders.cost_line不存在。)这是数据的样子。

OL.ORDER_NUMB OL.COST_LINE O.CUSTOMER_NUMB C.CUSTOMER_FIRST_NAME C.CUSTOMER_LAST_NAME
--
1             1.45         2014            Julio                 Savell
1             2.33         2014            Julio                 Savell
1             1.45         2014            Julio                 Savell
2             1.45         2014            Julio                 Savell
2             1.45         2014            Julio                 Savell
3             13.00        2014            Julio                 Savell

可以按order_lines.cost_line分组,但它不会为您提供任何有用的信息。此查询

select order_lines.cost_line, orders.customer_numb
from order_lines
inner join orders on orders.customer_numb = order_lines.customer_numb
group by order_lines.cost_line;

应该返回这样的内容。

OL.COST_LINE O.CUSTOMER_NUMB 
--
1.45         2014
2.33         2014
13.00        2014

非常有用。

如果您对订单行项目的总和感兴趣,则需要确定要分组(汇总)的列。如果按订单编号进行分组(汇总),您将获得三行。如果按客户编号对(汇总)进行分组,您将获得一行。