Puoi raggruppare la maggior parte dei costi in un'unica query principale in un CTE
e riutilizza il risultato più volte.
Ciò restituisce una unica riga con tre colonne chiamato dopo ogni type
(come richiesto nel commento
):
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;
Dovrebbe funzionare per Postgres 9.3. In Postgres 9.4 puoi utilizzare il nuovo aggregato FILTER
clausola:
count(*) FILTER (WHERE key = 'disable_student_nav' AND value = 'False') AS spn
, count(*) FILTER (WHERE key = 'pacing' AND value = 'teacher') AS tp
Dettagli per entrambe le varianti di sintassi:
La condizione contrassegnava problem?
potrebbe essere un grosso problema di prestazioni, a seconda del tipo di dati di cai.end_time
. Per prima cosa, non è sargable
. E se è un timestamptz
type, l'espressione è difficile da indicizzare, perché il risultato dipende dall'impostazione del fuso orario corrente della sessione, che può anche portare a risultati diversi se eseguita in fusi orari diversi.
Confronta:
- Estrarre due query dalla stessa tabella
- Sottrai le ore da adesso( ) funzione
- Ignora del tutto i fusi orari in Rails e PostgreSQL
Devi solo nominare il fuso orario che dovrebbe definire la tua data. Prendendo come esempio il mio fuso orario a Vienna:
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'
Puoi fornire un semplice timestamptz
anche i valori. Potresti anche solo:
WHERE cai.end_time >= '2015-09-12'::date
AND cai.end_time < '2015-09-12'::date + 1
Ma la prima variante non dipende dall'impostazione del fuso orario corrente.
Spiegazione dettagliata nei link sopra.
Ora la query può utilizzare il tuo indice e dovrebbe essere molto più veloce se nella tabella sono presenti molti giorni diversi.