从CASE WHEN语句中取出相关子查询

时间:2016-08-12 20:27:22

标签: sql oracle correlated-subquery case-when

我在Oracle中有一个employee表,可以有1或2" future"表future_jobs中的工作,某种业务规则,例如

| 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的两行中最早的日期,{{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

但是,我想知道是否有另一种方法可以从CASE WHEN语句中取出相关的子查询?有没有办法在不使用相关子查询的情况下执行此操作?我需要在单个语句中完成此操作,而不是使用| 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 | .... | 子句类型解决方案。

2 个答案:

答案 0 :(得分: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作为第一个未来的工作。

答案 1 :(得分:1)

实际上第二个想法你甚至不需要最大开始日期而你不需要嵌套选择来获得一个行号,你可以在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

我喜欢Gordon考虑窗口函数,但我使用MAX()和COUNT()来测试你的subselect的条件。但是和他一样,我并不积极,我完全理解你所希望的逻辑。

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