Mescolando insieme Connect da, join interno e somma con Oracle
-
05-10-2019 - |
Domanda
Ho bisogno di aiuto con una query di Oracle.
Qui è la mia messa a punto:
Ho 2 tabelle denominate rispettivamente "compiti" e "schede". La tabella "compiti" è un ricorsiva, in questo modo ogni attività può avere più attività secondarie. Ogni scheda attività è associata un'attività (non necessariamente il task "root") e contiene il numero di ore di lavoro su di esso.
Esempio:
Attività
id: 1 | NOME: Task A | parent_id: NULL
id: 2 | Nome: Task A1 | parent_id: 1
id: 3 | Nome: Task A1.1 | parent_id: 2
id: 4 | Nome: Task B | parent_id: NULL
id: 5 | Nome: Task B1 | parent_id: 4
Schede attività
id: 1 | task_id: 1 | ore: 1
id: 2 | task_id: 2 | ore: 3
id: 3 | task_id: 3 | ore: 1
id: 5 | task_id: 5 | ore: 1 ...
Cosa voglio fare:
Voglio una query che restituirà la somma di tutte le ore di lavoro su una "gerarchia delle attività". Se diamo uno sguardo l'esempio precedente, Vuol dire vorrei avere i seguenti risultati:
compito A - 5 hour (s) | compito B - 1 ora (s)
In un primo momento ho provato questo
SELECT TaskName, Sum(Hours) "TotalHours"
FROM (
SELECT replace(sys_connect_by_path(decode(level, 1, t.name), '~'), '~') As TaskName,
ts.hours as hours
FROM tasks t INNER JOIN timesheets ts ON t.id=ts.task_id
START WITH PARENTOID=-1
CONNECT BY PRIOR t.id = t.parent_id
)
GROUP BY TaskName Having Sum(Hours) > 0 ORDER BY TaskName
E quasi lavoro. L'unico problema è che se non ci sono scheda attività per un'attività root, salterà tutta hieararchy ... ma ci potrebbe essere schede per le righe figlio ed è esattamente ciò che accade con Task B1. So che è il "join interna" parte che sta causando il mio problema, ma io non sono sicuro di come posso liberarmi di esso.
Qualsiasi idea di come risolvere questo problema?
Grazie
Soluzione
Sarebbe qualcosa di simile a questo lavoro? Ho avuto casi simili ai tuoi, e ho semplicemente rimosso il join dalla query gerarchica e applicai soltanto in seguito per evitare di perdere le righe.
SELECT TaskName, Sum(ts.hours) "TotalHours"
FROM (
SELECT replace(sys_connect_by_path(decode(level, 1, t.name), '~'), '~') As TaskName, t.id
FROM tasks t
START WITH PARENTOID=-1
CONNECT BY PRIOR t.id = t.parent_id
) tasks
INNER JOIN timesheets ts ON tasks.id=ts.task_id
GROUP BY TaskName Having Sum(ts.hours) > 0 ORDER BY TaskName
Altri suggerimenti
Hai provato questo?
SELECT TaskName, Sum(Hours) "TotalHours"
FROM (
SELECT replace(sys_connect_by_path(decode(level, 1, t.name), '~'), '~') As TaskName,
ts.hours as hours
FROM timesheets ts LEFT OUTER JOIN tasks t ON t.id=ts.task_id
START WITH PARENTOID=-1
CONNECT BY PRIOR t.id = t.parent_id
)
GROUP BY TaskName Having Sum(Hours) > 0 ORDER BY TaskName
Se si utilizza join esterno sinistro al posto del normale join, è possibile ottenere l'output.
SELECT TaskName, Sum(Hours) "TotalHours"
FROM (
SELECT replace(sys_connect_by_path(decode(level, 1, t.name), '~'), '~') As TaskName,
ts.hours as hours
FROM tasks t,timesheets ts where t.id=ts.task_id(+)
START WITH PARENTOID=-1
CONNECT BY PRIOR t.id = t.parent_id
)
GROUP BY TaskName Having Sum(Hours) > 0 ORDER BY TaskName