2010-05-27 5 views
4

오라클 쿼리에 도움이 필요합니다. 내가 "작업"및 "작업 표"각각라는 두 테이블이함께 섞어서 연결하십시오, 내부 조인 및 Oracle 합계

:

여기 내 설정입니다. "tasks"테이블은 재귀 적 테이블이며, 각 태스크는 여러 하위 작업을 가질 수 있습니다. 각 작업 표는 작업 (반드시 "루트"작업 일 필요는 없음)과 연결되어 있으며 작업 한 시간 수를 포함합니다.

예 :

작업

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에서 발생하는 작업과 정확히 일치한다는 것입니다. 내 문제의 원인이되는 것이 "내부 결합"부분 인 것을 알고 있지만 어떻게 제거 할 수 있는지 잘 모르겠습니다.

이 아이디어를 어떻게 해결할 수 있습니까?

고맙습니다.

+0

테이블의 순서를 바꾸고 왼쪽 외부 조인을 사용하면 시간 시트가 없을 때도 작업을 수행 할 수 있다고 생각합니다. 어쩌면 그럴 수 있을까요? – FrustratedWithFormsDesigner

+0

도움 주셔서 감사합니다. 필자의 경우 왼쪽 조인을 수행하면 테이블이 잘 색인화되어 있지만 모든 주요 성능 문제가 발생합니다. –

답변

3

이 작품은 마음에 드시겠습니까? 나는 당신과 비슷한 케이스를 가졌고 단순히 계층 적 쿼리에서 조인을 제거하고 나중에 행을 잃지 않도록하기 위해 조인을 적용했습니다.

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 
+0

감사합니다. 나는 이것이 트릭을하고 있다고 생각한다. 몇 가지 테스트를 더해야하며이를 공식 답변으로 표시 할 것입니다. –

0

정상 결합 대신 왼쪽 외부 결합을 사용하면 출력이 나타날 수 있습니다.

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 
+0

나는 그가 테이블의 순서를 뒤집어 야한다고 생각한다. 왜냐하면 그는 대응하는 타임 쉬트가없는 작업을 원하기 때문이다. 현재 그는 왼쪽 바깥 쪽으로 바뀌면 해당 작업이없는 작업 표를 얻습니다. – FrustratedWithFormsDesigner

+0

FrustratedWithFormsDesigner : 맞습니다. 아니면 바깥 쪽 외부 조인도 사용할 수 있습니다. – Bharat

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 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 
+0

도움 주셔서 감사합니다! 이미 왼쪽 외부 조인 옵션을 시도했지만 쿼리 속도가 엄청나게 빠릅니다. 어쩌면 그 테이블의 인덱스를 다시 한 번 살펴 봐야 할 것 같습니다. 어딘가에 하나가없는 것 같습니다. 그러나 현재 RenderLn이 제안한 해결책이 제가 찾고있는 것입니다. 다시 한 번 도움을 주셔서 감사합니다. –

+0

내가 (이 쿼리를 보면서) 생각할 수있는 인덱스는'timesheets','task_id'의 인덱스입니다 (tasks.id는 이미 인덱스라고 가정합니다). 하지만 일반적으로 외부 조인은 내부보다 느립니다. – FrustratedWithFormsDesigner