Cột Lỗi không tồn tại trong một cột CHỌN với truy vấn THAM GIA và NHÓM THEO


7

Tôi đang sử dụng PostgreSQL 9.1 với ứng dụng Ruby on Rails.

Tôi đang cố gắng liệt kê phiên bản cuối cùng của mỗi "khoản phí" (trong bảng lịch sử của mình: hist_version_chargees) thuộc cùng một id dự án (proj_sous_projet_id = 2).

Điều này khiến tôi sử dụng hàm tổng hợp max () và áp dụng kết quả cho hàm THAM GIA trên cùng một bảng vì PostgreQuery không cho phép sử dụng các cột trong mệnh đề SELECT nếu chúng không xuất hiện trong mệnh đề GROUP BY, ALTHOUGH sử dụng max () có nghĩa là rõ ràng tôi quan tâm đến hàng chứa các giá trị tối đa!

Đây là truy vấn của tôi:

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;

Thông báo lỗi tôi nhận được:

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

Tôi cũng đã thử với "last_v.lv" nhưng lỗi vẫn như cũ.

Nếu bất cứ ai có ý tưởng về những gì sai, cô ấy được chào đón nhiều hơn.

=== CẬP NHẬT ===

Theo * a_horse_with_no_name * và câu trả lời của Colin , cuối cùng tôi đã kết thúc với truy vấn sau:

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;

Nó nhanh hơn một chút với một ĐẶT HÀNG B BYNG.

Tôi cũng đã thử truy vấn với mệnh đề CÓ. Mặc dù "đẹp hơn", nó tạo ra phí xử lý bổ sung. Vì tôi biết tôi sẽ không sử dụng lại trong tương lai truy vấn phụ hai lần trở lên trong cùng một truy vấn chính, tôi vẫn ổn khi sử dụng truy vấn phụ đơn giản.

Dù sao cũng cảm ơn * a_horse_with_no_name * và Colin 't Hart . Tôi đã học được nhiều điều!


2
" Không cho phép sử dụng các cột trong mệnh đề SELECT nếu chúng không xuất hiện trong mệnh đề GROUP BY ", mọi DBMS hợp lý khác cũng vậy.
a_horse_with_no_name

Có, nhưng, như đã giải thích ở đây: rpbouman.blogspot.se/2007/05/debunking-group-by-myths.html , tiêu chuẩn SQL 2003 định nghĩa nên có thể sử dụng cột phụ thuộc chức năng.
Douglas


1
@a_horse_with_no_name Bạn nói đúng. nhưng truy vấn trên không hợp lệ, thậm chí theo tiêu chuẩn 2003 vì nó sử dụng bí danh (được xác định trong SELECTdanh sách) trong FROMmệnh đề (thực ra là ONphần nhưng vẫn nằm trong mệnh đề TỪ)!
ypercubeᵀᴹ

@a_horse_with_no_name: Postgresql đang diễn giải "phụ thuộc chức năng" tiêu chuẩn bằng cách liên kết thuật ngữ với khóa chính. Tuy nhiên, tôi đang nói về "lẽ thường". Nếu bạn tìm thấy một giá trị max (), postgresql đã biết trên hàng wich, giá trị max () này được lưu trữ. Vì vậy, postgresql có thể truy cập bất kỳ cột nào bất kể mệnh đề GROUP BY có hàm tổng hợp như max (). Đây chỉ là một câu hỏi về logic và lẽ thường. Bất cứ cách nào querry của tôi là không chính xác, và cảm ơn rất nhiều vì đã chỉ cho tôi lỗi ngoặc đơn.
Douglas

Câu trả lời:


9

Bạn có thể muốn một cái gì đó như thế này:

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;

Một giải pháp có thể (vì không cần tham gia) sẽ là:

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;

Như Colin đã chỉ ra, điều này cũng có thể được viết là:

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;

1
@Doumund: sử dụng các chức năng của cửa sổ có thể mang lại cho bạn hiệu suất tốt hơn. Bạn có thể so sánh các kế hoạch thực hiện để tìm ra kế hoạch nào hiệu quả hơn.
a_horse_with_no_name

Ồ Chức năng cửa sổ. Đây là một thế giới hoàn toàn mới đối với tôi. Có vẻ như đầy đủ hơn. Cảm ơn rất nhiều, tôi sẽ nghiên cứu sâu về vấn đề này. Chỉ cần một câu hỏi "hv" có liên quan gì trong querry của bạn? Tôi có thể thấy "hvc" có thể được liên kết với hist_versions_chargees với mệnh đề AS bị thiếu, nhưng hv có phải là hàm hay chỉ là lỗi chính tả?
Douglas

1
@Doumund: hvlà bí danh cho bảng dẫn xuất (còn gọi là "truy vấn phụ"). Và bạn đã đúng, tôi quên mất bí danh bên trong bảng dẫn xuất.
a_horse_with_no_name

Bạn có thể làm cho giải pháp thứ hai thậm chí đẹp hơn bằng cách sử dụng a with clause. Ưu điểm lớn là nếu bạn quyết định trong tương lai, bạn cần sử dụng truy vấn con hai lần, bạn có thể tham chiếu nó theo tên, trong khi với phương pháp truy vấn phụ, bạn phải lặp lại truy vấn phụ.
Colin 't Hart

1
@ Colin'tHart: Tôi biết;) Tôi chỉ không muốn giới thiệu quá nhiều điều mới (Và tôi muốn bằng cách nào đó ở gần với truy vấn ban đầu).
a_horse_with_no_name
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.