188

I am getting ORA-00979 with the following query:

SELECT cr.review_sk, cr.cs_sk, cr.full_name,
tolist(to_char(cf.fact_date, 'mm/dd/yyyy')) "appt",
cs.cs_id, cr.tracking_number
from review cr, cs, fact cf
where cr.cs_sk = cs.cs_sk
and UPPER(cs.cs_id) like '%' || UPPER(i_cs_id) || '%'
and row_delete_date_time is null
and cr.review_sk = cf.review_wk (+)
and cr.fact_type_code (+) = 183050
GROUP BY cr.review_sk, cr.cs_sk, cf.fact_date, cr.tracking_number
ORDER BY cs.cs_id, cr.full_name;

I couldn't find any examples that had both GROUP BY and ORDER BY clauses in the same query. I tried removing each field from the group by one at a time, but am still getting the same error.

Ben
  • 51,770
  • 36
  • 127
  • 149
Theresa
  • 3,515
  • 10
  • 42
  • 47

10 Answers10

276

You must put all columns of the SELECT in the GROUP BY or use functions on them which compress the results to a single value (like MIN, MAX or SUM).

A simple example to understand why this happens: Imagine you have a database like this:

FOO BAR
0   A
0   B

and you run SELECT * FROM table GROUP BY foo. This means the database must return a single row as result with the first column 0 to fulfill the GROUP BY but there are now two values of bar to chose from. Which result would you expect - A or B? Or should the database return more than one row, violating the contract of GROUP BY?

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • even those that are in the ORDER BY clause? I don't have those two in my GROUP BY. – Theresa Oct 05 '09 at 15:09
  • 7
    No, you do not need to put them in your order by clause – Xaisoft Oct 05 '09 at 15:10
  • 4
    I tried adding the two columns in the ORDER BY to the GROUP BY. That worked. Thanks! – Theresa Oct 05 '09 at 15:12
  • 1
    Or to put it another way: If you have two columns and group by the first, that means you'll have several values from the second column per result row. Since there is only a single result row but many values to choose from, which one should the DB return? The first it stumbles upon? – Aaron Digulla Oct 08 '09 at 08:23
  • 11
    @AaronDigulla That's what MySQL does, and the world didn't end :p – Chris Baker Aug 27 '14 at 21:32
  • @Chris: Yeah, well, I prefer software which doesn't hide stupid mistakes from me which take endless hours to find :-) – Aaron Digulla Aug 28 '14 at 09:01
  • 1
    I partially agree. But assume the following case: there are 4 columns: A,B, C and D. Now I set (A,B,C) as a composite key. Then "select A,B,max(C), D ... group by A, B" is not ambiguous, since for each combination of A,B and C, D is already defined. Still oracle refuses to do its job. – g.a Mar 06 '17 at 17:17
  • 1
    The `A, B` grouping would have several potential values for `C` and `D`. The `MAX()` function returns the *group's* maximum for that field *only* - it does not return the whole row, nor could it. Firstly, even though the maximum value of `C` will be unique within its group in this scenario, in others it may not be. e.g. A count of Employees for each Store might have two records with the maximum value. Secondly, if you had also had `MAX( E )` then the two `MAX()` values could easily come from different records within the group. – toonice Apr 19 '17 at 00:02
23

Include in the GROUP BY clause all SELECT expressions that are not group function arguments.

Ram Sharma
  • 8,676
  • 7
  • 43
  • 56
Xaisoft
  • 45,655
  • 87
  • 279
  • 432
9

Too bad Oracle has limitations like these. Sure, the result for a column not in the GROUP BY would be random, but sometimes you want that. Silly Oracle, you can do this in MySQL/MSSQL.

BUT there is a work around for Oracle:

While the following line does not work

SELECT unique_id_col, COUNT(1) AS cnt FROM yourTable GROUP BY col_A;

You can trick Oracle with some 0's like the following, to keep your column in scope, but not group by it (assuming these are numbers, otherwise use CONCAT)

SELECT MAX(unique_id_col) AS unique_id_col, COUNT(1) AS cnt 
FROM yourTable GROUP BY col_A, (unique_id_col*0 + col_A);
Peter O.
  • 32,158
  • 14
  • 82
  • 96
Joseph Lust
  • 19,340
  • 7
  • 85
  • 83
  • @GlennFromIowa given my pseudo table isn't rigorously defined above, and that I not longer work for a firm with 11g, I can't provide a better example, though it was a problem when I last tested it. – Joseph Lust Nov 21 '15 at 00:14
  • 6
    Just out of curiosity what is an example of when you would want a random result? I can't think of any reason you would want to group by FOO and get a random row for BAR. – Kyle Bridenstine Oct 17 '17 at 17:48
  • Starting from Oracle Database 19c, fetch a value from random row is possible by using `any_value` keyword. You can refer to my answer for the example, or check the documentation here [Oracle docs blog](https://blogs.oracle.com/sql/post/how-to-select-the-top-n-rows-per-group-with-sql-in-oracle-database#top-n-per-group). – Yodi S. Oct 18 '22 at 07:42
7

If you do grouping by virtue of including GROUP BY clause, any expression in SELECT, which is not group function (or aggregate function or aggregated column) such as COUNT, AVG, MIN, MAX, SUM and so on (List of Aggregate functions) should be present in GROUP BY clause.

Example (correct way) (here employee_id is not group function (non-aggregated column), so it must appear in GROUP BY. By contrast, sum(salary) is a group function (aggregated column), so it is not required to appear in the GROUP BYclause.

   SELECT employee_id, sum(salary) 
   FROM employees
   GROUP BY employee_id; 

Example (wrong way) (here employee_id is not group function and it does not appear in GROUP BY clause, which will lead to the ORA-00979 Error .

   SELECT employee_id, sum(salary) 
   FROM employees;

To correct you need to do one of the following :

  • Include all non-aggregated expressions listed in SELECT clause in the GROUP BY clause
  • Remove group (aggregate) function from SELECT clause.
BobRodes
  • 5,990
  • 2
  • 24
  • 26
fg78nc
  • 4,774
  • 3
  • 19
  • 32
3

You should do the following:

SELECT cr.review_sk, 
       cr.cs_sk, 
       cr.full_name,
       tolist(to_char(cf.fact_date, 'mm/dd/yyyy')) "appt",
       cs.cs_id, 
       cr.tracking_number
from review cr, cs, fact cf
where cr.cs_sk = cs.cs_sk
       and UPPER(cs.cs_id) like '%' || UPPER(i_cs_id) || '%'
       and row_delete_date_time is null
       and cr.review_sk = cf.review_wk (+)
       and cr.fact_type_code (+) = 183050
GROUP BY cr.review_sk, cr.cs_sk, cf.fact_date, cr.tracking_number, cs.cs_id, cr.full_name
ORDER BY cs.cs_id, cr.full_name;
Pavel Zimogorov
  • 1,387
  • 10
  • 24
2

Same error also come when UPPER or LOWER keyword not used in both place in select expression and group by expression .

Wrong :-

select a , count(*) from my_table group by UPPER(a) .

Right :-

select UPPER(a) , count(*) from my_table group by UPPER(a) .
Vijay
  • 4,694
  • 1
  • 30
  • 38
1

In addition to the other answers, this error can result if there's an inconsistency in an order by clause. For instance:

select 
    substr(year_month, 1, 4)
    ,count(*) as tot
from
    schema.tbl
group by
    substr(year_month, 1, 4)
order by
    year_month
3pitt
  • 899
  • 13
  • 21
1

Adding an alternative solution for @Joseph Lust's answer regarding random rows in each group. This is made possible in Oracle Database 19c or newer by using any_value keyword. Here is an example:

select customer_id,
       max ( order_datetime ),
       any_value ( store_id ),
       any_value ( order_status ),
       any_value ( order_id )
from   co.orders
group  by customer_id;
Yodi S.
  • 106
  • 1
  • 5
0

The group by is used to aggregate some data, depending on the aggregate function, and other than that you need to put column or columns to which you need the grouping.

for example:

select d.deptno, max(e.sal) 
from emp e, dept d
where e.deptno = d.deptno
group by d.deptno;

This will result in the departments maximum salary.

Now if we omit the d.deptno from group by clause it will give the same error.

cнŝdk
  • 31,391
  • 7
  • 56
  • 78
Muhammad Nadeem
  • 368
  • 4
  • 7
  • 21
0

The answer of "Aaron Digulla" (the first at this time) inspired my solution for the same error code using Spring Boot 2 (JPA / Hibernate) and CriteriaQuery / CriteriaBuilder.

Make a List of selects, and add it to your criteriaQuery.multiselect()

List<Selection> selects = new ArrayList<>();
    selects.add(seccionRoot.get("id"));
    selects.add(synSeccionRoot.get("DDF"));
    selects.add(synSeccionRoot.get("TTYU"));
    selects.add(synSeccionRoot.get("4567"));
    selects.add(seccionRoot.get("22").get("223"));
    selects.add(tasaRoot.get("price"));
    selects.add(tasaRoot.get("chair"));

    cq.multiselect(selects.toArray(Selection[]::new));

Then you can cast the List to an Expression[]

cq.groupBy(selects.toArray(Expression[]::new));
ieselisra
  • 387
  • 4
  • 16