web-dev-qa-db-ja.com

JOINおよびGROUP BYクエリを使用したSELECTでエラー「列が存在しません」

Ruby on RailsアプリケーションでPostgreSQL 9.1を使用しています。

同じプロジェクトID(proj_sous_projet_id = 2)に属する(「履歴」テーブル:hist_version_chargesに)各「課金」の最新バージョンをリストしようとしています。

これにより、max()集約関数を使用し、結果が同じテーブルのJOIN関数に適用されます。これは、PostgreSQLがSELECT句で列を使用することを承認していないためです。 ()最大値を含む行に明らかに興味があることを意味します!

これは私のクエリです:

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;

私が得たエラーメッセージ:

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

「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;

1つのORDER BYを使用すると、わずかに高速になります。

WITH句を使用したクエリも試しました。 「ナイス」ですが、追加の処理料金が発生します。将来、同じメインクエリでサブクエリを2回以上再利用しないことがわかっているので、単純なサブクエリを使用しても問題ありません。

とにかく* a_horse_with_no_name *とColin 't Hartに感謝します。多くのことを学びました!

7
Douglas

あなたはおそらく次のようなものを望みます:

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;

おそらく(結合が必要ないため)より高速なソリューションは次のとおりです。

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;

コリンが指摘したように、これは次のように書くこともできます。

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;