2016-08-12 1 views
0

오라클에 employee 테이블이 있습니다.이 테이블은 일종의 비즈니스 규칙 인 테이블 future_jobs에 "미래"작업이 1,2 개있을 수 있습니다.상관 관계가있는 서브 쿼리를 케이스에서 꺼내십시오. 문

| employee_id | job_id | job_start_date | job_end_date | 
|-------------|--------|----------------|--------------| 
| 1   | 127589 | 12-SEP-2016 | 25-DEC-2016 | 
| 1   | 834780 | 26-DEC-2016 | 08-AUG-2017 | 
| 2   | 800253 | 20-OCT-2016 | 13-APR-2017 | 

특정 매개 변수로 저장 프로 시저를 호출하여 향후 각 작업에 대한 설명을 얻어야합니다. F1F2이며, 내림차순은 job_start_date입니다. 위의 예에서, 사람 job_start_date = 12-SEP-2016job_id = 127589 아래 행에 대해 실행되는 쿼리, employee_id = 1위한 두 열 중 빠른 날짜가 employee_id = 1 위해, get_description(emp.employee_id, 'F1') 호출되어야하고 job_id = 834780위한 get_description(emp.employee_id, 'F2').

employee_id = 2의 경우 향후 작업이 하나뿐이므로 이후 쿼리로 get_description(emp.employee_id, 'F1')을 호출해야합니다. 현재 다음 검색어로 관련 정보를 가져올 수 있습니다.

select 
    emp.employee_id, 
    case 
     when fj.job_start_date = (select max(job_start_date) 
            from future_jobs 
            where employee_id = fj.employee_id 
            group by employee_id 
            having count(employee_id) > 1) 
     then get_description(emp.employee_id, 'F2') 
     else get_description(emp.employee_id, 'F1') 
    end job_description, 
    fj.job_start_date 
    jd.some_additional_columns 
from employees emp 
join future_jobs fj 
    on emp.employee_id = fj.employee_id 
join job_details jd 
    on jd.job_id = fj.job_id 
    and jd.job_start_date = fj.job_start_date 
    and jd.job_end_date = fj.job_end_date 

| employee_id | job_description | job_start_date | jd.columns | 
|-------------|----------------------|----------------|--------------| 
| 1   | 1st future job desc | 12-SEP-2016 | ....   | 
| 1   | 2nd future job desc | 26-DEC-2016 | ....   | 
| 2   | 1st future job desc | 20-OCT-2016 | ....   | 

그러나 CASE WHEN 문에서 상관 하위 쿼리를 가져 오는 다른 방법이 있는지 알고 싶습니다. 상관 하위 쿼리를 사용하지 않고도이를 수행 할 수있는 방법이 있습니까? 나는 이것을 WITH 절 유형의 솔루션을 사용하는 대신 한 문장으로 처리해야합니다.

답변

2

난 그냥 윈도우 함수를 원한다고 생각 :

select emp.employee_id, 
     (case when fj.seqnum = 1 
      then get_description(emp.employee_id, 'F1') 
      else get_description(emp.employee_id, 'F2') 
     end) as job_description, 
     jd.some_additional_columns 
from employees emp join 
    (select fj.*, 
      row_number() over (partition by employee_id order by fj.job_start_date) as seqnum 
     from future_jobs fj 
    ) fj 
    on emp.employee_id = fj.employee_id join 
    job_details jd 
    on jd.job_id = fj.job_id and 
     jd.job_start_date = fj.job_start_date and 
     jd.job_end_date = fj.job_end_date; 

아니에요 100 % 확인 로직이 정확하게 맞습니다. 그것은 귀하의 설명을 따르고 첫 번째 미래의 직업에 F1을 사용합니다.

+0

감사합니다. 그게 내가 찾고 있던거야. 쿼리가 반환해야하는 내용을 설명하기 위해 설명을 업데이트했습니다. 이 솔루션의 성능과 질문의 성능을 어떻게 비교합니까? 어떤 조건에서 파티셔닝과 분석 기능이 더 잘 수행됩니까? – Malvon

1

실제로 최대 시작 날짜가 필요없고 행 번호를 얻으려면 중첩 된 선택이 필요하지 않으므로 count (*)를 창 명령으로 사용할 수 있습니다. .

select 
    emp.employee_id, 
    case 
     when COUNT(*) OVER (PARTITION BY fj.employee_id ORDER BY fj.job_start_date) > 1 
     then get_description(emp.employee_id, 'F2') 
     else get_description(emp.employee_id, 'F1') 
    end job_description, 
    jd.some_additional_columns 
from 
    employees emp 
    join future_jobs fj 
    on emp.employee_id = fj.employee_id 
    join job_details jd 
    on jd.job_id = fj.job_id 
    and jd.job_start_date = fj.job_start_date 
    and jd.job_end_date = fj.job_end_date 

나는 고든은 윈도우 함수의 생각을 좋아하지만 내가 MAX()를 사용하고 COUNT()를 통해 당신의 부속 선택의 당신의 조건을 테스트합니다. 그러나 나는 그와 같이 나는 네가 원하는 논리를 완전히 이해할만큼 긍정적이지 않다.

select 
    emp.employee_id, 
    case 
     when fj.job_start_date = MAX(fj.job_start_date) OVER (PARTITION BY fj.employee_id) 
      AND COUNT(*) OVER (PARTITION BY fj.employee_id) > 1 
     then get_description(emp.employee_id, 'F2') 
     else get_description(emp.employee_id, 'F1') 
    end job_description, 
    jd.some_additional_columns 
from 
    employees emp 
    join future_jobs fj 
    on emp.employee_id = fj.employee_id 
    join job_details jd 
    on jd.job_id = fj.job_id 
    and jd.job_start_date = fj.job_start_date 
    and jd.job_end_date = fj.job_end_date 

실행 카운트 예

DECLARE @Table AS TABLE (A CHAR(1),P INT) 
INSERT INTO @Table (A,P) VALUES ('A',1),('B',1),('C',2),('D',2) 

SELECT 
    * 
    ,COUNT(*) OVER (PARTITION BY P ORDER BY A) as RunningCount 
FROM 
    @Table 
+0

감사합니다. Matt. 나는 그 질문을 갱신했다. 당신의 솔루션도 작동합니다. 가능한 두 가지 경우가 있다고 가정 할 때, 우리는 MAX()와 COUNT() 집계를 제거하고 고든 (Gordon)과 같은 것을 실행시킬 수 있습니다. – Malvon

+0

사실 자신의 솔루션이 중첩 된 선택이기 때문에 우리 솔루션 간의 성능 차이가 무엇인지 궁금 할 것입니다. case 문에서 count()가 약간 더 빨라질 것입니다. – Matt

+0

분석 함수없이 쿼리를 수행하는 방법이 있는지 궁금합니다. – Malvon

관련 문제