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()ignorujeNULLhodnoty.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 hoursNicméně pokud je možné, že všechny sloupce výběru mají
NULLnebo prázdné řetězce, zabalte součty doCOALESCEjednou.
Používámnumericmístofloat, bezpečnější alternativa pro minimalizaci zaokrouhlovacích chyb. -
Váš pokus získat odlišné hodnoty ze spojení
usersatasksje marné, protože se připojíte ktaskješ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
dateztimestampmůžete jednoduše přenést nadate:tl.created_on::date AS changedayAle mnohem lepší je testovat s původními hodnotami v
WHEREklauzule neboJOINstav (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 borderVšimněte si, že datum literál se převede na
timestampv00:00dne 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 taskpřidejteWHEREklauzule:WHERE EXISTS (SELECT 1 FROM tasks t1 WHERE t1.assignee_id = u.id) -
Nejdůležitější :
LEFT [OUTER] JOINzachová všechny řádky nalevo od spojení. PřidáníWHEREdoložka vpravo tabulka může tento efekt zrušit. Místo toho přesuňte výraz filtru doJOINdolož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,projectsatask_log_entriespřed levým připojením všech kusers- bez poddotazu. -
Aliasy tabulek zjednodušit psaní složitých dotazů.