I have an employee
table in Oracle that can have either 1 or 2 "future" jobs in table future_jobs
, a business rule of some sort, eg
| 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 |
I have to get the description of each future job by invoking a stored procedure with a specific parameter, eg F1
and F2
, based on a descending order of job_start_date
. In example above, for employee_id = 1
, when the query below is executed for job_id = 127589
row, since job_start_date = 12-SEP-2016
is the earliest date among the two rows for employee_id = 1
, get_description(emp.employee_id, 'F1')
should be called, and get_description(emp.employee_id, 'F2')
for job_id = 834780
.
and for employee_id = 2
, since there is only one future job, get_description(emp.employee_id, 'F1')
should be invoked with the query below. Currently, I can pull the relevant information with the following query:
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 | .... |
However, I would like to know if there is another way to take the correlated sub-query out of CASE WHEN statement? Is there even a way to do it without using the correlated sub-query? I need to have this done in a single statement rather than using WITH
clause type solution.
I think you just want window functions:
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;
I'm not 100% sure the logic is exactly correct. It follows your description and uses F1
for the first future job.
Actually on second thought you don't even need the max start date and you don't need the nested select to get a row number you can do it right in the case statement with count(*) as a window function.
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
I like Gordon was thinking of window functions but I uses MAX() and COUNT() over to test your conditions of your subselect. But like him I am not positive I fully understand your desired logic.
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
Running Count Example
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.