带有 JOIN 和 GROUP BY 查询的 SELECT 中的错误“列不存在”

Dou*_*las 7 postgresql join select group-by

我将 PostgreSQL 9.1 与 Ruby on Rails 应用程序一起使用。

我正在尝试列出属于同一项目 ID (proj_sous_projet_id = 2) 的每个“费用”(在我的历史表中:hist_version_charges)的最后一个版本。

这使我使用 max() 聚合函数并将结果应用于同一个表上的 JOIN 函数,因为如果 SELECT 子句中的列未出现在 GROUP BY 子句中,则 PostgreSQL 没有授权使用它们,但使用最大值() 显然我对包含最大值的行感兴趣!

这是我的查询:

SELECT h_v_charges.*, 
       max(last_v.version) as lv 
FROM hist_versions_charges h_v_charges 
    JOIN hist_versions_charges last_v 
      ON h_v_charges.version = lv 
    AND h_v_charges.proj_charge_id = last_v.proj_charge_id 
GROUP BY last_v.proj_sous_projet_id, 
         last_v.proj_charge_id 
HAVING last_v.proj_sous_projet_id = 2 
ORDER BY h_v_charges.proj_charge_id ASC;
Run Code Online (Sandbox Code Playgroud)

我得到的错误信息:

ERROR:  column "lv" does not exist
LINE 1: ..._versions_charges last_v ON h_v_charges.version = lv AND h_v...
                                                             ^
********** Error **********

ERROR: column "lv" does not exist
SQL state: 42703
Character: 147
Run Code Online (Sandbox Code Playgroud)

我也尝试过“last_v.lv”,但错误仍然相同。

如果有人知道出了什么问题,她非常受欢迎。

=== 更新 ===

根据 * a_horse_with_no_name * 和Colin 't Hart 的回答,我最终得到了以下查询:

SELECT *
FROM (
    SELECT *, max(version) OVER (PARTITION BY proj_charge_id) AS lv
    FROM hist_versions_charges
    WHERE proj_sous_projet_id = 2) AS hv
WHERE hv.lv = hv.version
ORDER BY hv.proj_charge_id ASC;
Run Code Online (Sandbox Code Playgroud)

使用单个 ORDER BY 稍微快一点。

我也尝试使用 WITH 子句进行查询。虽然“更好”,但它会产生额外的处理费用。据我所知,将来我不会在同一个主查询中重复使用子查询两次或更多次,我可以使用简单的子查询。

无论如何都要感谢 *a_horse_with_no_name* 和 Colin't Hart。我学到了很多东西!

a_h*_*ame 9

你可能想要这样的东西:

SELECT h_v_charges.*, 
       last_v.last_version
FROM hist_versions_charges h_v_charges 
  JOIN (select proj_charge_id, 
               max(version) as last_version
        from hist_versions_charges 
        where proj_sous_projet_id = 2  
        group by proj_charge_id
  ) last_v  
  ON h_v_charges.version = last_v.last_version
 AND h_v_charges.proj_charge_id = last_v.proj_charge_id 
ORDER BY h_v_charges.proj_charge_id ASC;
Run Code Online (Sandbox Code Playgroud)

一个可能(因为不需要连接)更快的解决方案是:

select *
from (
   select hvc.*, 
          row_number() over (partition by proj_charge_id order by version desc) as rn
   from hist_versions_charges as hvc
   where proj_sous_projet_id = 2  
) as hv
where rn = 1
order by hv.proj_charge_id ASC;
Run Code Online (Sandbox Code Playgroud)

正如 Colin 所指出的,这也可以写成:

with hv as (
  select hvc.*, 
         row_number() over (partition by proj_charge_id order by version desc) as rn
  from hist_versions_charges as hvc
  where proj_sous_projet_id = 2  
) 
select *
from hv
where rn = 1
order by hv.proj_charge_id ASC;
Run Code Online (Sandbox Code Playgroud)