在 SELECT 语句中按错误分组,导致 Oracle 中出现 ORA-00979 错误代码

Posted

技术标签:

【中文标题】在 SELECT 语句中按错误分组,导致 Oracle 中出现 ORA-00979 错误代码【英文标题】:Group by error within SELECT statement causing ORA-00979 error code in Oracle 【发布时间】:2016-10-30 21:21:09 【问题描述】:

我正在尝试运行以下代码:

SELECT BOOK.BOOK_NUM AS "Book Number",
       BOOK.BOOK_TITLE AS "Book Title",
       BOOK.BOOK_SUBJECT AS "BOOK SUBJECT",
       ROUND(AVG(BOOK.BOOK_COST),2) as "Subject Avg",
       (BOOK_COST - ROUND(AVG(BOOK.BOOK_COST),2)) AS "COST DIFFERENCE" 
FROM BOOK
GROUP BY BOOK.BOOK_NUM, BOOK.BOOK_TITLE, BOOK.BOOK_SUBJECT

但是,当我这样做时,我得到一个错误

ORA-00979: 不是 GROUP BY 表达式

删除后似乎没有出现该问题:

(BOOK_COST - ROUND(AVG(BOOK.BOOK_COST),2)) AS "COST DIFFERENCE"

来自select 声明。

我知道 GROUP BY 语句需要 select 语句中所有不是函数的值,我认为我的满足了这个要求。

任何帮助将不胜感激!

【问题讨论】:

你的 dbms 是什么? @rory.ap “ORA”可能代表什么? :) 您期望成本差异列返回什么?记住您返回的是每个标题的平均价格 @obe -- 我的意思是,OP 需要适当地标记问题。 您需要在 GROUP BY 中包含 BOOK_COST。 【参考方案1】:

错误的直接原因是您将 BOOK_COST 作为标量引用(不在分组函数内),但它不是 GROUP BY 表达式的一部分。

显而易见的“解决方案”是将BOOK_COST 添加到GROUP BY 列表中,但我怀疑这会给您想要的答案。事实上,我怀疑您在 GROUP BY 中的列已经比您真正想要的要多。

看起来你想要的是:

计算每个学科的平均书籍成本 列出所有书籍,并为每本书显示该书籍的成本与其主题内的平均成本之间的差异

如 Gordon 的回答所示,实现此目的的一种方法是使用带有适当分区子句的 AVG() 的窗口版本。如果我对您的要求的猜测是正确的,那么您实际上想要的是:

SELECT BOOK.BOOK_NUM AS "Book Number",
       BOOK.BOOK_TITLE AS "Book Title",
       BOOK.BOOK_SUBJECT AS "BOOK SUBJECT",
       ROUND(AVG(BOOK.BOOK_COST) OVER (PARTITION BY BOOK.BOOK_SUBJECT), 2) as "Subject Avg",
       (BOOK_COST - ROUND(AVG(BOOK.BOOK_COST) OVER (PARTITION BY BOOK.BOOK_SUBJECT), 2)) AS "COST DIFFERENCE" 
FROM BOOK;

(您也可以使用子查询来避免两次写出窗口函数,但这对于这个答案并不重要。)

只是为了说明(或者如果您碰巧在旧版本的 Oracle 上),这里有一种不使用窗口函数的方法:

WITH subjects as (
  SELECT book.book_subject, round(avg(book.book_cost),2) as avg_cost
  FROM book
  GROUP BY book.book_subject
)
SELECT
  book.book_num,
  book.book_title,
  book.book_subject,
  subjects.avg_cost,
  book.book_cost - subjects.avg_cost
FROM
  book
JOIN
  subjects ON subject.book_subject = book.book_subject

这会对表进行一次查询以查找每个主题的平均成本,然后将其与基表连接起来,这样您就可以计算每本书的差异。

【讨论】:

为情况提供上下文。我正在上入门课程,所以你使用的一些功能/术语我还没有被指导过,所以我提前道歉,有些信息可能会让我头晕目眩:/我对此的要求是:“写一个查询,将显示给定主题内书籍的平均成本以及书籍成本与平均成本之间的差异。显示书号、书名、图书主题、平均成本和差异。按图书主题排序。"跨度> 【参考方案2】:

我认为您正在寻找窗口函数,而不是聚合函数:

SELECT BOOK.BOOK_NUM AS "Book Number",
       BOOK.BOOK_TITLE AS "Book Title",
       BOOK.BOOK_SUBJECT AS "BOOK SUBJECT",
       ROUND(AVG(BOOK.BOOK_COST) OVER (PARTITION BY BOOK.BOOK_NUM, BOOK.BOOK_TITLE, BOOK.BOOK_SUBJECT), 2) as "Subject Avg",
       (BOOK_COST - ROUND(AVG(BOOK.BOOK_COST) OVER (PARTITION BY BOOK.BOOK_NUM, BOOK.BOOK_TITLE, BOOK.BOOK_SUBJECT), 2)) AS "COST DIFFERENCE" 
FROM BOOK;

这会保留数据中的所有原始行并在其中添加聚合列。

【讨论】:

除了基于列别名(以及我对数据的假设),我怀疑窗口函数应该只使用“PARTITION BY BOOK.BOOK_SUBJECT”。【参考方案3】:

group by的语义是:

查询的选择部分中的任何属性都应该是:

在群里

或者作为聚合函数的参数

在你的情况下,

(BOOK_COST - ROUND(AVG(BOOK.BOOK_COST),2)) AS "COST DIFFERENCE"

BOOK_COST 不在 group by 中,也不在聚合函数中。

【讨论】:

以上是关于在 SELECT 语句中按错误分组,导致 Oracle 中出现 ORA-00979 错误代码的主要内容,如果未能解决你的问题,请参考以下文章

在select sql语句中按前一行增加值列

如何在一行中按顺序对所有项目的总金额进行分组

在 bigquery Standard sql 中按问题分组,并且无法获取唯一记录

在嵌套选择查询中按条件分组后加入

Linq在C#中按2列分组[重复]

Oracle OCP提纲