7

我正在为即将到来的考试复习一些练习题,但我在完全理解 group by 时遇到了问题。我看到GROUP BY如下:将结果集按一列或多列分组。

我有以下数据库架构

在此处输入图像描述

在此处输入图像描述

我的查询

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

我很难理解
为什么我不能简单地使用 justGROUP BY orders.cost_line并按 cost_line 对数据进行分组?

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

很抱歉这篇长文,如果我错过了任何东西,我深表歉意。任何帮助将不胜感激。

4

2 回答 2

6

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

当您说group by customer_numb您知道 customer_numb 唯一标识客户表中的一行时(假设 customer_numb 是主键或备用键),因此任何给定的andcustomers.customer_numb都只有一个值。但是在解析时,Oracle 不知道,或者至少表现得好像它不知道。它说,有点恐慌,“如果一个单曲有多个值,我该怎么办?”customers.customer_first_namecustomers.customer_last_namecustomer_numbcustomer_first_name

大致规则是,子句中的select表达式可以使用子句中的表达式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)或使用列别名并对其排序selectalias

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

注意:我听说一些 RDBMS 将暗示分组的附加表达式,而没有明确说明它们。Oracle 不是这些 RDBMS 之一。

至于按两者分组customer_numbcost_line考虑一个有两个客户的数据库,1 和 2 有两个订单,每个订单:

Customer 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

最高的第一行sum(cost_line)不是花费最多的客户。

于 2012-10-23T04:47:18.177 回答
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

不是非常有用。

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

于 2012-10-23T02:46:04.200 回答