从 CASE WHEN 语句中取出相关子查询
Take Correlated Sub-query Out of CASE WHEN Statement
我在 Oracle 中有一个 employee
table,它可以在 table future_jobs
中有 1 个或 2 个 "future" 个作业,一些业务规则排序,例如
| 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
行执行下面的查询时,由于 job_start_date = 12-SEP-2016
是 employee_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
子句类型解决方案。
我认为您只需要 window 个函数:
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
作为未来的第一份工作。
实际上转念一想,您甚至不需要最大开始日期,也不需要嵌套的 select 来获取行号,您可以在 case 语句中使用 count(* ) 作为 window 函数。
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 正在考虑 window 函数,但我使用 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
我在 Oracle 中有一个 employee
table,它可以在 table future_jobs
中有 1 个或 2 个 "future" 个作业,一些业务规则排序,例如
| 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
行执行下面的查询时,由于 job_start_date = 12-SEP-2016
是 employee_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
子句类型解决方案。
我认为您只需要 window 个函数:
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
作为未来的第一份工作。
实际上转念一想,您甚至不需要最大开始日期,也不需要嵌套的 select 来获取行号,您可以在 case 语句中使用 count(* ) 作为 window 函数。
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 正在考虑 window 函数,但我使用 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