Skip to content
Advertisement

ORA-00937: not a single-group group function Workaround

select
        o.customer_id,
        c.cust_first_name,
        c.cust_last_name,
        c.income_level,
        to_char(o.order_date, 'DD-MON-YY HH12:MI') as order_date,
        ROW_NUMBER() over (partition by o.customer_id order by o.order_date) as order#,
        o.order_total,
        lag(o.order_total, 1, 0) over (partition by o.customer_id order by o.customer_id) 
        + lag(o.order_total, 2, 0) over (partition by o.customer_id order by o.customer_id) as last_two_orders_sum,
        min(o.order_date) keep (dense_rank last order by o.customer_id) as first_order_total
from orders o, customers c
where o.customer_id = c.customer_id

This is my query which produces this error:

ORA-00937: not a single-group group function

Expected result for the last column – first order of every customer:

expected results screenshot

I know that I have to use GROUP BY clause to handle this error, but it seems rather inappropriate to group by all the other columns.. I know that this is a limitation in Oracle 11g and this issue is fixed in 12c, but I still need some kind of workaround.

Tried:

CTEs –> kinda weird to have single select in a CTE

Subquery –> can’t figure out the right syntax and it produces a mess

Any help is appreciated!

Advertisement

Answer

Rather than the MIN(...) KEEP (...) aggregation function, you want to use MIN(...) KEEP (...) OVER (...) analytic function or, possibly without the KEEP, use MIN(...) OVER (PARTITION BY ...):

select
        o.customer_id,
        c.cust_first_name,
        c.cust_last_name,
        c.income_level,
        to_char(o.order_date, 'DD-MON-YY HH12:MI') as order_date,
        ROW_NUMBER() over (partition by o.customer_id order by o.order_date)
          as order#,
        o.order_total,
        lag(o.order_total, 1, 0)
          over (partition by o.customer_id order by o.customer_id) 
        + lag(o.order_total, 2, 0)
          over (partition by o.customer_id order by o.customer_id)
          as last_two_orders_sum,
        MIN(o.order_date) OVER (PARTITION BY o.customer_id) as first_order_date,
        MIN(o.order_total) KEEP (DENSE_RANK FIRST ORDER BY o.order_date)
                           OVER (PARTITION BY o.customer_id) as first_order_total
from    orders o
        INNER JOIN customers c
        ON o.customer_id = c.customer_id

Note: Also, use ANSI join syntax rather than the legacy comma-join syntax.

I know that this is a limitation in Oracle 11g and this issue is fixed in 12c, but I still need some kind of workaround.

No, this is not something that you fix by upgrading to a later version. It is a fundamental issue with your query that you are using an mix of aggregated and non-aggregated columns and, as the error message implies, you do not have a GROUP BY clause that includes all of the non-aggregated columns.

The solution is to not use any aggregation functions and change to only use analytic functions.

db<>fiddle here

Advertisement