14

In this pgexercises about joining 3 different tables, the answer is given as following:

select mems.firstname || ' ' || mems.surname as member, 
    facs.name as facility, 
    case 
        when mems.memid = 0 then
            bks.slots*facs.guestcost
        else
            bks.slots*facs.membercost
    end as cost
        from
                cd.members mems                
                inner join cd.bookings bks
                        on mems.memid = bks.memid
                inner join cd.facilities facs
                        on bks.facid = facs.facid
        where
        bks.starttime >= '2012-09-14' and 
        bks.starttime < '2012-09-15' and (
            (mems.memid = 0 and bks.slots*facs.guestcost > 30) or
            (mems.memid != 0 and bks.slots*facs.membercost > 30)
        )
order by cost desc;

Why can't I refer to the cost alias in the SELECT list in the WHERE clause?
If I run the same query with:

        ...
        where
        bks.starttime >= '2012-09-14' and 
        bks.starttime < '2012-09-15' and
        cost > 30
order by cost desc;

an error occurs:

ERROR: column "cost" does not exist

It's clear with me from this answer that it's because of the order of evaluation. But why order by cost desc; is allowed?

Community
  • 1
  • 1
Lamnk
  • 524
  • 1
  • 5
  • 15
  • 2
    Vide [Conceptual Order of Evaluation of a Select Statement](http://tinman.cs.gsu.edu/~raj/sql/node22.html). – klin Jun 26 '16 at 16:40
  • at first I misunderstood your question :) now I completely aggre with statement above – Vao Tsun Jun 26 '16 at 16:47
  • 2
    The cost alias doesn't exist prior to the recordset being returned when the where statement is applied. where as the ORDER BY statement is applied after the recordset has been created meaning that the column alias is then availble. – Matt Jun 26 '16 at 18:32
  • To work around that, I turned `SELECT ... c1 FROM t1 WHERE c1 ...` into `SELECT ... FROM (SELECT ... c1 FROM t1) t2 WHERE t2.c1 ...`. Not sure how that might affect performance. – x-yuri Aug 27 '18 at 13:50

1 Answers1

24

You ask two questions:
1.

Why can't I refer to the SELECT cost alias at the WHERE clause?

2.

But why order by cost desc; is allowed?


The manual has an answer for both of them here:

An output column's name can be used to refer to the column's value in ORDER BY and GROUP BY clauses, but not in the WHERE or HAVING clauses; there you must write out the expression instead.

It's defined by the SQL standard and the reason is the sequence of events in a SELECT query. At the time WHERE clauses are applied, output columns in the SELECT list have not yet been computed. But when it comes to ORDER BY, output columns are readily available.

So while this is inconvenient and confusing at first, it still kind of makes sense.

Related:

Community
  • 1
  • 1
Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228