In Postgresql 9.1+ I'm trying to filter a result set in the WHERE clause using a ROW_NUMBER() aliased field. This query works fine:
SELECT inv.client_pk, 
       inv.invoice_pk, inv.contract_pk, 
       ROW_NUMBER() OVER ( PARTITION BY inv.client_pk ORDER BY inv.client_pk) as row_number 
FROM controllr.client as cli 
  LEFT JOIN controllr.invoice as inv ON inv.client_pk = cli.client_pk                              
WHERE client_status != 3;
But when I add the "row_number" in WHERE:
SELECT inv.client_pk, 
       inv.invoice_pk, inv.contract_pk, 
       ROW_NUMBER() OVER ( PARTITION BY inv.client_pk ORDER BY inv.client_pk) as row_number 
FROM controllr.client as cli 
  LEFT JOIN controllr.invoice as inv ON inv.client_pk = cli.client_pk                              
WHERE client_status != 3 
  AND row_number <= 3;
It gives me an error:
column "row_number" does not exist
When the field "row_number" clearly exists as a aliased field.
What I'm doin wrong?
ps: I already tried with HAVING clause
The ROW_NUMBER function cannot currently be used in a WHERE clause. Derby does not currently support ORDER BY in subqueries, so there is currently no way to guarantee the order of rows in the SELECT subquery.
Using subquery:
SELECT 
    *
FROM
    (SELECT 
         inv.client_pk, inv.invoice_pk, inv.contract_pk, 
         ROW_NUMBER() OVER (PARTITION BY inv.client_pk ORDER BY inv.client_pk) AS row_number 
     FROM 
         controllr.client as cli 
     LEFT JOIN 
         controllr.invoice as inv ON inv.client_pk = cli.client_pk                              
     WHERE 
         client_status != 3) AS sub
WHERE 
    row_number <= 3;
Using CTE:
WITH cte AS 
(
    SELECT 
        inv.client_pk, inv.invoice_pk, inv.contract_pk, 
        ROW_NUMBER() OVER ( PARTITION BY inv.client_pk ORDER BY inv.client_pk) AS row_number 
    FROM 
        controllr.client as cli 
    LEFT JOIN 
        controllr.invoice as inv ON inv.client_pk = cli.client_pk                              
    WHERE 
        client_status != 3
)
SELECT *
FROM cte
WHERE row_number <= 3;
The reason why you are receiving that error is because the WHERE clause is processed before the SELECT clause. Therefore, the engine is unable to see row_number as a column when trying to process the condition ... row_number <= 3 with your original query.
Also, using CTE has the same performance of using a subquery but it does improve readability.
Using subquery:
SELECT client_pk, invoice_pk, contract_pk
FROM
(
SELECT inv.client_pk, inv.invoice_pk, inv.contract_pk,
                     ROW_NUMBER() OVER
           ( PARTITION BY inv.client_pk
                      ORDER BY inv.client_pk) as row_number
FROM  controllr.client as cli 
LEFT JOIN  controllr.invoice as inv ON inv.client_pk = cli.client_pk 
WHERE client_status !=3  
) t                            
     WHERE row_number <= 3;
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With