PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Câu lệnh GROUP BY + CASE

Truy vấn của bạn sẽ hoạt động - ngoại trừ việc bạn đang gặp phải xung đột đặt tên hoặc chỉ nhầm lẫn với cột đầu ra (CASE biểu thức) với cột nguồn result , có nội dung khác.

...
GROUP BY model.name, attempt.type, attempt.result
...

Bạn cần GROUP BY CASE của bạn biểu thức thay vì cột nguồn của bạn:

...
GROUP BY model.name, attempt.type
       , CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END
...

Hoặc cung cấp bí danh cột khác với bất kỳ tên cột nào trong FROM danh sách - hoặc nếu không cột đó sẽ được ưu tiên:

SELECT ...
     , CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END AS result1
...
GROUP BY model.name, attempt.type, result1
...

Tiêu chuẩn SQL khá đặc biệt về mặt này. Trích dẫn hướng dẫn sử dụng tại đây:

Tên của cột đầu ra có thể được sử dụng để tham chiếu đến giá trị của cột trong ORDER BYGROUP BY các mệnh đề, nhưng không có trong WHERE hoặc HAVING mệnh đề; ở đó bạn phải viết ra biểu thức để thay thế.

Và:

Nếu một ORDER BY biểu thức là một tên đơn giản phù hợp với cả tên cột đầu ra và tên cột đầu vào, ORDER BY sẽ giải thích nó thông qua tên cột đầu ra. Điều này ngược lại với lựa chọn GROUP BY sẽ làm cho trong cùng một tình huống. Sự mâu thuẫn này được tạo ra để tương thích với tiêu chuẩn SQL.

In đậm nhấn mạnh của tôi.

Có thể tránh được những xung đột này bằng cách sử dụng tham chiếu theo vị trí (số thứ tự) trong GROUP BYORDER BY , tham chiếu đến các mục trong SELECT danh sách từ trái sang phải. Xem giải pháp bên dưới.
Hạn chế là điều này có thể khó đọc hơn và dễ bị chỉnh sửa trong SELECT danh sách (người ta có thể quên điều chỉnh các tham chiếu vị trí cho phù hợp).

Nhưng bạn không không phải thêm cột day vào GROUP BY mệnh đề, miễn là nó giữ một giá trị không đổi (CURRENT_DATE-1 ).

Được viết lại và đơn giản hóa với cú pháp JOIN phù hợp và các tham chiếu vị trí, nó có thể trông như thế này:

SELECT m.name
     , a.type
     , CASE WHEN a.result = 0 THEN 0 ELSE 1 END AS result
     , CURRENT_DATE - 1 AS day
     , count(*) AS ct
FROM   attempt    a
JOIN   prod_hw_id p USING (hard_id)
JOIN   model      m USING (model_id)
WHERE  ts >= '2013-11-06 00:00:00'  
AND    ts <  '2013-11-07 00:00:00'
GROUP  BY 1,2,3
ORDER  BY 1,2,3;

Cũng lưu ý rằng tôi đang tránh tên cột time . Đó là một từ dành riêng và không bao giờ được sử dụng làm định danh. Ngoài ra, "thời gian" của bạn rõ ràng là một timestamp hoặc day , vì vậy điều đó hơi gây hiểu lầm.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. in giá trị của một biến trong postgresql

  2. Lưu trữ dữ liệu được mã hóa trong Postgres

  3. Chọn nhiều giá trị max () bằng cách sử dụng một câu lệnh SQL

  4. Làm cách nào để cập nhật + tham gia vào PostgreSQL?

  5. Về lợi ích của các đường dẫn được sắp xếp