2016-08-12 66 views
0

我在Oracle中有一個employee表,它可以在表future_jobs中有一個或兩個「將來」作業,這是某種商業規則(例如,使相關的子查詢超出CASE WHEN語句

| 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的降序排列。在上面的例子中,對於employee_id = 1,當針對job_id = 127589行執行以下查詢時,因爲job_start_date = 12-SEP-2016employee_id = 1的兩行中最早的日期,應調用get_description(emp.employee_id, 'F1')get_description(emp.employee_id, 'F2')job_id = 834780

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

實際上,第二個想法是,你甚至不需要最大開始日期,並且你不需要嵌套select來獲得一個行號,你可以在case語句中用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

謝謝馬特。我更新了這個問題。你的解決方案也可以。考慮到有兩種可能的情況,我們可以消除'MAX()'和'COUNT()'聚合並執行像Gordon想出的那樣。 – Malvon

+0

是的,但是因爲他的解決方案是一個嵌套選擇,我很想知道我們的解決方案之間的性能差異。我敢打賭,case語句中的count()會稍微快一點 – Matt

+0

我想知道是否有辦法在沒有分析函數的情況下執行查詢。 – Malvon