Forespørgslen kan sandsynligvis forenkles til:
SELECT u.name AS user_name
, p.name AS project_name
, tl.created_on::date AS changeday
, coalesce(sum(nullif(new_value, '')::numeric), 0)
- coalesce(sum(nullif(old_value, '')::numeric), 0) AS hours
FROM users u
LEFT JOIN (
tasks t
JOIN fixins f ON f.id = t.fixin_id
JOIN projects p ON p.id = f.project_id
JOIN task_log_entries tl ON tl.task_id = t.id
AND tl.field_id = 18
AND (tl.created_on IS NULL OR
tl.created_on >= '2013-09-08' AND
tl.created_on < '2013-09-09') -- upper border!
) ON t.assignee_id = u.id
WHERE EXISTS (SELECT 1 FROM tasks t1 WHERE t1.assignee_id = u.id)
GROUP BY 1, 2, 3
ORDER BY 1, 2, 3;
Dette returnerer alle brugere, der nogensinde har haft en opgave.
Plus data pr. projekt og dag hvor data findes i det angivne datointerval i task_log_entries .
Vigtige punkter
-
aggregerfunktionen
sum()ignorererNULLværdier.COALESCE()pr. række er ikke påkrævet mere, så snart du omformulerer beregningen som forskellen på to summer:,coalesce(sum(nullif(new_value, '')::numeric), 0) - coalesce(sum(nullif(old_value, '')::numeric), 0) AS hoursMen hvis det er muligt, at alle kolonner i et udvalg har
NULLeller tomme strenge, pak summene ind iCOALESCEén gang.
Jeg brugernumerici stedet forfloat, sikrere alternativ til at minimere afrundingsfejl. -
Dit forsøg på at få forskellige værdier fra sammenføjningen af
usersogtaskser nyttesløst, da du deltager itaskendnu en gang længere nede. Gør hele forespørgslen flad for at gøre den enklere og hurtigere. -
Disse positionsreferencer er blot en notationsbekvemmelighed:
GROUP BY 1, 2, 3 ORDER BY 1, 2, 3... gør det samme som i din oprindelige forespørgsel.
-
For at få en
datefra ettimestampdu kan blot caste tildate:tl.created_on::date AS changedayMen det er meget bedre at teste med originale værdier i
WHEREklausul ellerJOINtilstand (hvis muligt, og det er muligt her), så Postgres kan bruge almindelige indekser på kolonnen (hvis tilgængelig):AND (tl.created_on IS NULL OR tl.created_on >= '2013-09-08' AND tl.created_on < '2013-09-09') -- next day as excluded upper borderBemærk, at en dato bogstavelig konverteres til et
timestampkl.00:00dagens på dit nuværende tidspunkt zone . Du skal vælge den næste dag og ekskluder det som øvre grænse. Eller angiv et mere eksplicit tidsstempel, f.eks.'2013-09-22 0:0 +2':: timestamptz. Mere om udelukkelse af øvre kant: -
For kravet
every user who has ever been assigned to a tasktilføjWHEREklausul:WHERE EXISTS (SELECT 1 FROM tasks t1 WHERE t1.assignee_id = u.id) -
Vigtigst :En
LEFT [OUTER] JOINbevarer alle rækker til venstre for sammenføjningen. Tilføjelse af enWHEREklausul til højre tabel kan annullere denne effekt. Flyt i stedet filterudtrykket tilJOINklausul. Mere forklaring her: -
Parentes kan bruges til at fremtvinge den rækkefølge, som tabeller samles i. Sjældent nødvendigt til simple forespørgsler, men meget nyttigt i dette tilfælde. Jeg bruger funktionen til at deltage i
task,fixins,projectsogtask_log_entriesfør du forlader det hele tilusers- uden underforespørgsel. -
Tabelaliasser gør det nemmere at skrive komplekse forespørgsler.