I’m writing a query where I’m doing a union on several different tables to combine them to make one item.
Let’s make up an example where I have a table Purchases
and a table Leases
and I’m creating a new result for Sales
. On one of the tables, I’m basing the Description
based on a different column. Ex:
SELECT
u.id as UserId,
p.name as Name,
p.email as Email,
'Purchase' as Table,
p.id as SaleId,
p.status_id as SaleStatusId,
p.description as SaleDescription
FROM users u
INNER JOIN purchase p on u.id = p.user_id
UNION ALL
SELECT
u.id as UserId,
l.name as Name,
l.email as Email,
'Lease' as Table,
l.id as SaleId,
l.status_id as SaleStatusId,
CASE
WHEN l.status_id = 2 THEN 'Finalized Lease'
ELSE 'Pending Lease'
END as SaleDescription
FROM users u
INNER JOIN lease l on u.id = l.user_id
This is all fine and dandy, but the problem comes when I’m trying to search on this description I’m adding. So I’m trying to add where clauses like:
SELECT
u.id as UserId,
p.name as Name,
p.email as Email,
'Purchase' as Table,
p.id as SaleId,
p.status_id as SaleStatusId,
p.description as SaleDescription
FROM users u
INNER JOIN purchase p on u.id = p.user_id
WHERE (@searchDescription = {} or p.description = any (@searchDescriptions))
UNION ALL
SELECT
u.id as UserId,
l.name as Name,
l.email as Email,
'Lease' as Table,
l.id as SaleId,
l.status_id as SaleStatusId,
CASE
WHEN l.status_id = 2 THEN 'Finalized Lease'
ELSE 'Pending Lease'
END as SaleDescription
FROM users u
INNER JOIN lease l on u.id = l.user_id
WHERE (@searchDescription = {} or SaleDescription = any (@searchDescriptions))
searchDescription
is a list of strings that if any match the SaleDescription, I want it returned. All others ignored.
So the first WHERE
statement works fine because it’s searching on an existing column. The second WHERE
does NOT work, since it can’t search a column that hasn’t "been populated yet", and I get this error:
There is a column named `SaleDescription` in table "*SELECT* 1", but it cannot be referenced from this part of the query
So basically I’m wondering how I can achieve this? How can I add a where
clause to a column that gets populated by a case
select
?
** Note this is dumby code, there may be errors– I haven’t tested it
2
Answers
CTE could be used to select columns needed way, then do filtering on CTE, like:
The reason you get that error is due to the logical [order of] query processing which is different to the order of clauses required by syntax rules. Whilst a "select query" starts with "select" according to syntax; it is NOT the first clause to be executed. The clauses that get the data (FROM & JOIN) and then filter that data (WHERE) are the first set of clauses to get executed.
What this means to your problem is that the column aliases established under the select clause are "not known" until the select clause is considered, and ths comes AFTER the where clause. Hence you get the type of error you encountered. (nb. This column alias not known problem is true for Postgres and many other RDBMS, but not all.)
To solve this there are several methods:
fiddle