在WHERE中使用ROW_NUMBER()别名

Pav*_*ine 2 sql postgresql

在PostgreSQL 9.1+中,我试图使用ROW_NUMBER()别名字段来过滤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;
Run Code Online (Sandbox Code Playgroud)

但是,当我在“ WHERE”中添加“ row_number”时:

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;
Run Code Online (Sandbox Code Playgroud)

它给我一个错误:

列“ row_number”不存在

当字段“ row_number”作为别名字段明确存在时。

我做错了什么?

ps:我已经尝试过HAVING子句

Mar*_*rro 5

使用子查询:

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;
Run Code Online (Sandbox Code Playgroud)

使用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;
Run Code Online (Sandbox Code Playgroud)

之所以收到该错误,是因为该WHERE子句在该SELECT子句之前被处理。因此,row_number在尝试... row_number <= 3使用原始查询处理条件时,引擎无法将其视为一列。

同样,使用CTE具有与使用子查询相同的性能,但是确实提高了可读性。