it-swarm.com.de

Fehler "Spalte existiert nicht" in einer SELECT mit JOIN- und GROUP BY-Abfrage

Ich verwende PostgreSQL 9.1 mit einer Ruby on Rails -Anwendung).

Ich versuche, die letzte Version jeder "Gebühr" (in meiner Verlaufstabelle: hist_version_charges) aufzulisten, die zu derselben Projekt-ID gehört (proj_sous_projet_id = 2).

Dadurch verwende ich die Aggregatfunktion max () und wende das Ergebnis auf eine JOIN-Funktion in derselben Tabelle an, in der PostgreSQL nicht berechtigt ist, die Spalten in der SELECT-Klausel zu verwenden, wenn sie nicht in der GROUP BY-Klausel ALTHOUGH mit max () meine natürlich interessiert mich die Zeile mit den Maximalwerten!

Das ist meine Frage:

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;

Die Fehlermeldung, die ich bekam:

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

Ich habe es auch mit "last_v.lv" versucht, aber der Fehler bleibt gleich.

Wenn jemand eine Vorstellung davon hat, was los ist, ist sie mehr als willkommen.

=== UPDATE ===

Nach den Antworten * a_horse_with_no_name * und Colin 't Hart kam ich schließlich zu folgender Abfrage:

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;

Mit einem einzigen ORDER BY geht es etwas schneller.

Ich habe auch die Abfrage mit einer WITH-Klausel versucht. Obwohl "schöner", entsteht eine zusätzliche Bearbeitungsgebühr. Da ich weiß, dass ich die Unterabfrage in Zukunft nicht zweimal oder mehrmals in derselben Hauptabfrage wiederverwenden werde, kann ich problemlos eine einfache Unterabfrage verwenden.

Trotzdem danke an * a_horse_with_no_name * und Colin 't Hart . Ich habe viele Dinge gelernt!

7
Douglas

Sie möchten wahrscheinlich so etwas:

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;

Eine möglicherweise (da kein Join erforderlich ist) schnellere Lösung wäre:

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;

Wie Colin betont hat, kann dies auch geschrieben werden als:

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;