Смешивание вместе соединения, внутреннее соединение и сумма с Oracle
-
05-10-2019 - |
Вопрос
Мне нужна помощь с запросом Oracle.
Вот моя настройка:
У меня есть 2 столы, называемые соответственно «заданиями» и «расписаниями». Таблица «Задачей» представляет собой рекурсивный, таким образом, каждая задача может иметь несколько подзадач. Каждый расписание связан с задачей (не обязательно «root» задачей) и содержит количество часов, работающих над ним.
Пример:
Задачи
ID: 1 | Имя: задание A | parent_id: null.
ID: 2 | Имя: задание A1 | parent_id: 1.
ID: 3 | Имя: задание A1.1 | parent_id: 2.
ID: 4 | Имя: задача B | parent_id: null.
ID: 5 | Имя: задача B1 | parent_id: 4.
Рассылки
ID: 1 | task_id: 1 | Часы: 1.
ID: 2 | task_id: 2 | Часы: 3.
ID: 3 | task_id: 3 | Часы: 1.
ID: 5 | task_id: 5 | Часы: 1 ...
Что я хочу сделать:
Я хочу запрос, который вернет сумму всех часов, работающих на «иерархии задач». Если мы посмотрим на предыдущий пример, это означает, что я хотел бы иметь следующие результаты:
Задача A - 5 часов (ы) | Задача B - 1 час (ы)
Сначала я попробовал это
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
И это почти работа. Единственная проблема заключается в том, что если нет расписания для корневой задачи, она пропустит всю хихарархию ... но могут быть расписания для дочерних строк, и именно то, что происходит с заданием B1. Я знаю, что это «внутренняя присоединение», которая вызывает мою проблему, но я не уверен, как я могу избавиться от этого.
Любая идея, как решить эту проблему?
Спасибо
Решение
Будет что-то вроде этой работы? У меня были случаи, похожие на ваши, и я просто удалил присоединение из иерархического запроса и применил его только потом, чтобы избежать потерять строки.
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
Другие советы
Вы пробовали это?
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
Если вы используете влево внешнее соединение вместо обычного присоединения, вы можете получить выход.
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