tags:

views:

473

answers:

4

I want to find the largest sale for each of my employees (and display the name of the employee). In MySQL, it's pretty straightforward:

select * 
  from employee, sale 
  where employee.id = sale.employee_id 
  group by employee_id 
  order by sale.total desc

This does pretty much what one would expect, it would return a list of employees and end up returning the largest sale record with the employee row.

But, Oracle does not allow you to return columns which are not group by expressions when a group by clause is used. Do this make what I do in MySQL "impossible" in Oracle? Or is there some workaround? I suppose I could perform some sort of subquery, but not sure if there is another way to do this that wouldn't quite be so complicated to construct.

+4  A: 

To get the largest sale you can use group by with the max function.

select e.name, max (s.total) 
  from employee e, sale s 
  where e.id = s.employee_id 
  group by e.name 
  order by s.total desc
  • I have made an assumption that the employee name is in the name column of the employee table. I have also aliased the employee table and sales tables.
  • If you would prefer to see the total sales for an employee, you can swap out max() and use sum() instead.
akf
Oh, duh, I guess max is what I want anyway, but how to get the name as well?
altCognito
what is the table/column name where you hold this info?
akf
Under employee...
altCognito
Check my edit, I have made a couple changes.
akf
+4  A: 

Get rid of your select * and replace it with just the columns you need and then group by all the "non-processed" columns.

You'll end up with something like:

select employee.id, employee.name, max(sale.total)
from employee, sale
where employee.id = sale.employee_id
group by employee.id, employee.name
order by max(sale.total) desc

It's a pain - I've had to do this many times before - but just add all the related columns to your group by

Brandon Belvin
* was for brevity. In my non-example I actually specify the columns. Yet I do find it incredibly annoying that I need to include every column that I intend to select I have to duplicate in the group by clause. So, to grab 12 columns turns my SQL statement into some ridiculous looking monstrosity. But, the point about max is well made.
altCognito
Sorry about the `*`. You don't always know from a random internet posting if the guy is abbreviating or actually executing it.And I understand about the monstrosity. Due to "curious" database design, I've had to include up to 12 columns in a `group by`. That was unpleasant.
Brandon Belvin
Well, it's pretty easy to get up to 12 columns in just a address table. Addr1,Addr2,City,State,Zip,Country,Long,Lat - and that's just the basic fields.
altCognito
+3  A: 

Congratulations, you've learned just enough to be dangerous!

What you really want is each employee's largest sale. Now it happens that sorting them by sales amount desc and then grouping them works in MySQL, even though that isn't legal according to ANSI SQL. (Basically, MySQL is arbitrarily grabbing the first row for each employee, and that "works" because of the sort.)

The right way to do this is not to rely on the side of effect of the sort doing what you want; instead you should explicitly ask for what you want: the largest sale for each employee. In SQL that's:

select employee.id, max( sale.total) 
from employee, sale 
where employee.id = sale.employee_id 
group by employee.id 
order by 2
tpdi
+1  A: 

If you want to select an employee with a highest sale, you don't need GROUP BY here at all.

All you need is to select the highest sale and join it back to the employees:

SELECT  *
FROM    (
        SELECT  sale.*, ROW_NUMBER() OVER (ORDER BY total DESC) AS rn
        FROM    sale
        ) s
JOIN    employee e
ON      e.id = s.employee_id
        AND s.rn = 1

This will select a single row with a total highest sale.

If you want to select per-employee highest sale, just add a PARTITION BY clause to your query:

SELECT  *
FROM    (
        SELECT  sale.*, ROW_NUMBER() OVER (PARTITION BY employee_id ORDER BY total DESC) AS rn
        FROM    sale
        ) s
JOIN    employee e
ON      e.id = s.employee_id
        AND s.rn = 1
Quassnoi