2016-08-12 7 views
0

私はemployeeというテーブルを1つまたは2つの "将来の"ジョブをテーブル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 | 

将来の各ジョブの説明は、特定のパラメータ(例: F1およびF2であり、降順であるjob_start_dateに基づいています。上記の例では、employee_id = 1の場合、次のクエリをjob_id = 127589行に対して実行すると、employee_id = 1の2つの行のうち最も早い日付がjob_start_date = 12-SEP-2016であるため、をjob_id = 834780と呼びます。

およびemployee_id = 2の場合、将来のジョブが1つしかないので、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節タイプの解法を使うのではなく、1つのステートメントで行う必要があります。

答えて

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

実際に2番目の考えでは、最大開始日も必要なく、行番号を取得するためにネストされたselectを必要としません。count(*)をウィンドウ関数としてcase文。

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

ありがとうございました。私は質問を更新しました。あなたのソリューションも機能します。可能なケースが2つあるとすれば、 'MAX()'と 'COUNT()'集約を取り除き、Gordonが思い付いたようなものを実行することができます。 – Malvon

+0

本当ですが、彼のソリューションはネストされた選択であるため、私たちのソリューションのパフォーマンスの違いを知りたいのです。 case文のcount()を少し速くすることを喜んでお勧めします。 – Matt

+0

解析関数なしでクエリを実行する方法があるのだろうかと思います。 – Malvon