Anda dapat menggabungkan sebagian besar biaya dalam satu kueri utama dalam CTE
dan gunakan kembali hasilnya beberapa kali.
Ini mengembalikan baris tunggal dengan tiga kolom dinamai menurut setiap type
(seperti yang diminta di komentar
):
WITH cte AS (
SELECT cai.id, cai.activity_id, cas.key, cas.value
FROM common_activityinstance cai
JOIN common_activityinstance_settings s ON s.activityinstance_id = cai.id
JOIN common_activitysetting cas ON cas.id = s.id
WHERE cai.end_time::date = '2015-09-12' -- problem?
AND cai.activity_type = 'QZ'
AND (cas.key = 'disable_student_nav' AND cas.value IN ('True', 'False') OR
cas.key = 'pacing' AND cas.value IN ('student', 'teacher'))
)
SELECT *
FROM (
SELECT count(*) AS spf
FROM (
SELECT c.id
FROM cte c
JOIN quizzes_quiz q ON q.id = c.activity_id
WHERE q.name <> 'Exit Ticket Quiz'
AND (c.key, c.value) IN (('disable_student_nav', 'True')
, ('pacing', 'student'))
GROUP BY 1
HAVING count(*) = 2
) sub
) spf
, (
SELECT count(key = 'disable_student_nav' AND value = 'False' OR NULL) AS spn
, count(key = 'pacing' AND value = 'teacher' OR NULL) AS tp
FROM cte
) spn_tp;
Harus bekerja untuk Postgres 9.3. Di Postgres 9.4 Anda dapat menggunakan FILTER
agregat baru klausa:
count(*) FILTER (WHERE key = 'disable_student_nav' AND value = 'False') AS spn
, count(*) FILTER (WHERE key = 'pacing' AND value = 'teacher') AS tp
Detail untuk kedua varian sintaks:
Kondisi ditandai problem?
mungkin masalah kinerja yang besar, tergantung pada tipe data cai.end_time
. Pertama, ini bukan sargable
. Dan jika itu adalah timestamptz
ketik, ekspresinya sulit untuk diindeks, karena hasilnya bergantung pada pengaturan zona waktu sesi saat ini - yang juga dapat menghasilkan hasil yang berbeda ketika dieksekusi di zona waktu yang berbeda.
Bandingkan:
- Sustract dua kueri dari tabel yang sama
- Kurangi jam dari sekarang( ) fungsi
- Mengabaikan zona waktu sama sekali di Rails dan PostgreSQL
Anda hanya perlu memberi nama zona waktu yang seharusnya menentukan tanggal Anda. Mengambil zona waktu saya di Wina sebagai contoh:
WHERE cai.end_time >= '2015-09-12 0:0'::timestamp AT TIME ZONE 'Europe/Vienna'
AND cai.end_time < '2015-09-13 0:0'::timestamp AT TIME ZONE 'Europe/Vienna'
Anda dapat memberikan timestamptz
sederhana nilai-nilai juga. Anda bahkan bisa:
WHERE cai.end_time >= '2015-09-12'::date
AND cai.end_time < '2015-09-12'::date + 1
Namun varian pertama tidak bergantung pada pengaturan zona waktu saat ini.
Penjelasan detail pada link di atas.
Sekarang kueri dapat menggunakan indeks Anda dan akan jauh lebih cepat jika ada banyak hari berbeda di tabel Anda.