views:

331

answers:

3

Both the following two statements produce an error in Postgres:

SELECT substring(start_time,1,8) AS date, count(*) as total from cdrs group by date;
SELECT substring(start_time,1,8) AS date, count(*) as total from cdrs group by substring(start_time,1,8);

The error is:

column "cdrs.start_time" must appear in the GROUP BY clause or be used in an aggregate function

My reading of postgres docs is that both SELECT and GROUP BY can use an expression postgres 8.3 SELECT

The start_time field is a string and has a date/time in form ccyymmddHHMMSS. In mySQL they both produce desired and expected results:

+----------+-------+
| date     | total |
+----------+-------+
| 20091028 |     9 |
| 20091029 |   110 |
| 20091120 |    14 |
| 20091121 |     4 |
+----------+-------+
4 rows in set (0.00 sec)

I need to stick with Postgres (heroku). Any suggestions?

p.s. there is lots of other discussion around that talks about missing items in GROUP BY and why mySQL accepts this, why others don't ... strict adherence to SQL spec etc etc, but I think this is sufficiently different to 1062158/converting-mysql-select-to-postgresql and 1769361/postgresql-group-by-different-from-mysql to warrant a separate question.

A: 

Two simple things you might try:

  1. Upgrade to postgres 8.4.1
    Both queries Work Just Fine For Me(tm) under pg841

  2. Group by ordinal position
    That is, GROUP BY 1 in this case.

pilcrow
re 1., will see when heroku are upgrading!re 2., just tried, same error.Thanks.
Straff
+1  A: 

You did something else that you didn't describe in the question, as both of your queries work just fine. Tested on 8.5 and 8.3.8:

# create table cdrs (start_time text);
CREATE TABLE

# insert into cdrs (start_time) values ('20090101121212'),('20090101131313'),('20090510040603');
INSERT 0 3

# SELECT substring(start_time,1,8) AS date, count(*) as total from cdrs group by date;
   date   | total
----------+-------
 20090510 |     1
 20090101 |     2
(2 rows)

# SELECT substring(start_time,1,8) AS date, count(*) as total from cdrs group by substring(start_time,1,8);
   date   | total
----------+-------
 20090510 |     1
 20090101 |     2
(2 rows)
depesz
Quite right, there was an "ORDER BY start_time ASC" clause I'd left off thinking it would simplify the example, and thinking it was irrelevant based on the error message. Not so. Changing to "ORDER BY date ASC" or "ORDER BY substring(start_time,1,8) ASC" works and gives right result. Note that both mySQL and sqlite accept "ORDER BY start_time ASC" and the other two formats. It is a mis-leading error message but I should have provided full query above. Thanks for your help.
Straff
A: 

Just to summarise, error

column "cdrs.start_time" must appear in the GROUP BY clause or be used in an aggregate function

was caused (in this case) by ORDER BY start_time clause. Full statement needed to be either:

SELECT substring(start_time,1,8) AS date, count(*) as total FROM cdrs GROUP BY substring(start_time,1,8) ORDER BY substring(start_time,1,8);

or

    SELECT substring(start_time,1,8) AS date, count(*) as total FROM cdrs GROUP BY date ORDER BY date;
Straff