Dotaz lze pravděpodobně zjednodušit na:
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;
Tím se vrátí všichni uživatelé, kteří kdy měli nějaký úkol.
Plus data za projekty a den kde data existují v zadaném časovém období v task_log_entries
.
Hlavní body
-
souhrnná funkce
sum()
ignorujeNULL
hodnoty.COALESCE()
na řádek již není vyžadován, jakmile předěláte výpočet jako rozdíl dvou součtů:,coalesce(sum(nullif(new_value, '')::numeric), 0) - coalesce(sum(nullif(old_value, '')::numeric), 0) AS hours
Nicméně pokud je možné, že všechny sloupce výběru mají
NULL
nebo prázdné řetězce, zabalte součty doCOALESCE
jednou.
Používámnumeric
místofloat
, bezpečnější alternativa pro minimalizaci zaokrouhlovacích chyb. -
Váš pokus získat odlišné hodnoty ze spojení
users
atasks
je marné, protože se připojíte ktask
ještě jednou níž. Sjednoťte celý dotaz, aby byl jednodušší a rychlejší. -
Tyto polohové odkazy jsou jen vymožeností zápisu:
GROUP BY 1, 2, 3 ORDER BY 1, 2, 3
... uděláte to samé jako v původním dotazu.
-
Chcete-li získat
date
ztimestamp
můžete jednoduše přenést nadate
:tl.created_on::date AS changeday
Ale mnohem lepší je testovat s původními hodnotami v
WHERE
klauzule neboJOIN
stav (pokud je to možné a je to možné zde), takže Postgres může na sloupci použít prosté indexy (pokud jsou k dispozici):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 border
Všimněte si, že datum literál se převede na
timestamp
v00:00
dne ve vašem aktuálním čase zóna . Musíte vybrat další den a vyloučit to jako horní hranice. Nebo poskytněte explicitnější literál časového razítka, například'2013-09-22 0:0 +2':: timestamptz
. Více o vyloučení horního okraje: -
Pro požadavek
every user who has ever been assigned to a task
přidejteWHERE
klauzule:WHERE EXISTS (SELECT 1 FROM tasks t1 WHERE t1.assignee_id = u.id)
-
Nejdůležitější :
LEFT [OUTER] JOIN
zachová všechny řádky nalevo od spojení. PřidáníWHERE
doložka vpravo tabulka může tento efekt zrušit. Místo toho přesuňte výraz filtru doJOIN
doložka. Více vysvětlení zde: -
Závorky lze použít k vynucení pořadí, ve kterém jsou tabulky spojeny. Zřídka potřebné pro jednoduché dotazy, ale v tomto případě velmi užitečné. Tuto funkci používám k připojení k
task
,fixins
,projects
atask_log_entries
před levým připojením všech kusers
- bez poddotazu. -
Aliasy tabulek zjednodušit psaní složitých dotazů.