views:

1302

answers:

3

Say I have a table 'orders' created as:

CREATE TABLE orders (id SERIAL, 
                     customerID INTEGER,
                     timestamp BIGINT, 
                     PRIMARY KEY(id));

Timestamp being the UNIX timestamp. Now i want to select the ids of the LATEST orders for every customer. As a view would be nice.

however the following statement

CREATE VIEW lastOrders AS SELECT  id,
                                  customerID, 
                                  MAX(timestamp) 
                                  FROM orders 
                                  GROUP BY customerID;

Causes a postgre error:

ERROR: column "orders.id" must appear in the GROUP BY clause or be used in an aggregate function

What am I doing wrong?

+1  A: 

kquinns answer will fix the exception, but isn't what you are looking for.

I don't know the features of mysql but something like this would work with oracle:

select a.*
from 
    orders a, 
    (select customerID, max(timestamp) timestamp 
        from orders group by customerID
    ) b
where a.customer_id = b.customerID
and a.timestamp = b.timestamp

actually with oracle one could use analytic functions, but I do not think they are available in mysql

Jens Schauder
Just for your information: the poster referred to postgresql.
ChristopheD
Two typos: you miss a 'AS' between max(timestamp) and timestamp and the a.customer_id should been replaced by a.customerID
bortzmeyer
+8  A: 

For these kind of things you can use 2 approaches. One has been already shown by Jens.

Other, is to use "DISTINCT ON" clause:

CREATE VIEW lastOrders AS
SELECT
DISTINCT ON (customerID)
    id,
    customerID,
    timestamp
FROM orders
ORDER BY customerID, timestamp desc;
depesz
looked up DISTINCT ON in postgres doc. Just what I needed. Very Elegant. Thanks!
I agree. It's the sort of thing that comes up time and again, and Postgres's developers found a nice way of dealing with it. Shame it isn't part of standard SQL.
yukondude
Very nice use of DISTINCT
Luc M
+2  A: 

The following query should return only the very last order for each customer.

CREATE  VIEW last_orders AS
SELECT  id, customer_id, timestamp
FROM    orders AS o
WHERE   timestamp = (
            SELECT  MAX(timestamp)
            FROM    orders AS oi
            WHERE   o.customer_id = oi.customer_id
        );

(Assuming that you can't have two orders for a customer with the exact same timestamp value.)

Edit: Postgres's DISTINCT ON is a much niftier way of doing this. I'm glad I learned about it. But, the above works for other RDBMSs.

yukondude
Yes, Jens Schauder and depesz solutions are correct, too.
bortzmeyer
You're right. The others are correct as well.
yukondude