PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Pernyataan GROUP BY + CASE

Kueri Anda sudah berfungsi - kecuali Anda mengalami konflik penamaan atau hanya membingungkan kolom keluaran (CASE ekspresi) dengan kolom sumber result , yang memiliki konten berbeda.

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

Anda perlu GROUP BY CASE . Anda ekspresi alih-alih kolom sumber Anda:

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

Atau berikan alias kolom yang berbeda dari nama kolom apa pun di FROM list - atau kolom itu diutamakan:

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

Standar SQL agak aneh dalam hal ini. Mengutip manualnya di sini:

Nama kolom keluaran dapat digunakan untuk merujuk ke nilai kolom diORDER BY dan GROUP BY klausa, tetapi tidak dalam WHERE atau HAVING klausa; di sana Anda harus menuliskan ekspresinya.

Dan:

Jika ORDER BY ekspresi adalah nama sederhana yang cocok dengan nama kolom keluaran dan nama kolom masukan, ORDER BY akan menafsirkannya sebagai nama kolom keluaran. Ini adalah kebalikan dari pilihan yang GROUP BY akan membuat dalam situasi yang sama. Inkonsistensi ini dibuat agar kompatibel dengan standar SQL.

Tebal tekankan milikku.

Konflik ini dapat dihindari dengan menggunakan referensi posisi (nomor urut) di GROUP BY dan ORDER BY , mereferensikan item dalam SELECT daftar dari kiri ke kanan. Lihat solusi di bawah.
Kekurangannya adalah, ini mungkin lebih sulit dibaca dan rentan terhadap pengeditan di SELECT list (orang mungkin lupa untuk menyesuaikan referensi posisi yang sesuai).

Tapi Anda tidak harus menambahkan kolom day ke GROUP BY klausa, selama memiliki nilai konstan (CURRENT_DATE-1 ).

Ditulis ulang dan disederhanakan dengan sintaks GABUNG yang tepat dan referensi posisi akan terlihat seperti ini:

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;

Perhatikan juga bahwa saya menghindari nama kolom time . Itu adalah kata yang dicadangkan dan tidak boleh digunakan sebagai pengenal. Selain itu, "waktu" Anda jelas merupakan timestamp atau date , sehingga agak menyesatkan.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Pertemuan PostgreSQL Praha

  2. Tambahkan Tanda Plus/Minus ke Angka di PostgreSQL

  3. Cara Menginstal PostgreSQL 12 di Fedora 33

  4. Cara Menghitung Median di PostgreSQL

  5. Masukkan jika tidak ada, jika tidak kembalikan id di postgresql