优化查询,从过去2年中选择3种薪水

时间:2018-12-05 18:15:44

标签: sql oracle oracle11g bi-publisher

我有一个查询,该查询将显示2年内(如果有3年)过去的3个薪水。我已经查询并运行了,问题是,它的运行速度非常慢...我想知道是否有编写此查询的更好方法。我是oracle的新手。

这是我的桌子

TABLE 1: Salary 
ASSIGN_ID  | start_date  | end_date   |   salary  |
      1    |  11/27/2017 |  1/05/2018 |  50000.0  |
      2    |   1/06/2018 |  6/08/2018 |  76000.0  |
      3    |   6/09/2018 | 12/31/4712 |  80500.0  |

TABLE 2: Assignments
ASSIGN_ID | per_ID | start_date | end_date    | 
     1    |   1    |  11/2/2017 |  1/05/2018  | 
     2    |   1    |  1/06/2018 |  6/08/2018  |  
     3    |   1    |  6/09/2018 | 12/31/4712  | 
     4    |   2    |  5/12/2016 |  7/18/2017  | 
     5    |   2    |  7/19/2017 | 12/31/4712  |  

Table 3: Person

per_id | first_name | last_name | 
   1   |    John    |   Smith   |  
   2   |    Jane    |   Doe     |

如果结束日期当前在任务中处于活动状态,则默认为12/31/4712

我的查询如下:

SELECT
   per.first_name,
   per.last_name,
   (CASE WHEN sal1.start_date >= add_months(CURRENT_DATE, -24)
    THEN sal1.salary
    ELSE NULL END) oldest_salary,
   (CASE WHEN sal2.start_date >= add_months(CURRENT_DATE, -24) 
    THEN sal2.salary
    ELSE NULL END) prior_salary,
   sal3.salary current_salary,
FROM
   person per
INNER JOIN assignments asg1 ON asg1.per_id = per.per_id
INNER JOIN assignments asg2 ON asg2.per_id = asg1.per_id
INNER JOIN assignments asg3 ON asg3.per_id = asg2.per_id
INNER JOIN salary sal1 ON sal1.assign_id = asg1.assign_id
INNER JOIN salary sal2 ON sal2.assign_id = asg2.assign_id
INNER JOIN salary sal3 ON sal3.assign_id = asg3.assign_id
WHERE asg3.start_date =
        (SELECT MAX(asg.start_date
         FROM assignments asg
         WHERE asg.assign_id = asg3.assign_id)
AND (asg3.start_date - 1) BETWEEN asg2.start_date and asg2.end_date
AND (asg2.start_date - 1) BETWEEN asg1.start_date and asg1.end_date
AND sal1.salary != sal2.salary
AND sal2.salary != sal3.salary
ORDER BY 2,1

有没有更简单的方法来做到这一点?因为当我运行脚本时,它将永远处理。我想我可能需要更好的加入。就像我说的我是新手一样,对联接的理解也很薄弱。

1 个答案:

答案 0 :(得分:1)

一种简单的形式:

SELECT 
    z.first_name,
    z.last_name,
    --typical cross-db compatible pivot method
    MAX(CASE WHEN z.rown = 1 THEN z.salary END) as recentsalary,
    MAX(CASE WHEN z.rown = 2 THEN z.salary END) as oldersalary,
    MAX(CASE WHEN z.rown = 3 THEN z.salary END) as oldestsalary
FROM
(
    SELECT
       per.first_name,
       per.last_name,
      --number assignments from 1=recent to N older
       row_number() over(partition by a.per_id order by a.start_date desc) rown
       s.salary
    FROM --join up all
       person p
       INNER JOIN assignments a ON a.per_id = p.per_id
       INNER JOIN salary s ON s.assign_id = s.assign_id
    WHERE a.end_date > ADD_MONTHS(SYSDATE, -36) --only recent 3 years
) z
WHERE z.rown <= 3 --only the most recent 3 assignments
GROUP BY first_name, last_name --achieve pivot

它的工作原理是:

汇总所有数据,以便了解人员,任务和薪水

仅考虑3年前结束的任务

按从小到大的顺序编号作业(1 =最小)

将每人最近,最老和最老的薪水最高的3个编号分为3列