Оптимизированный запрос, который выбирает 3 зарплаты за последние 2 года - PullRequest
0 голосов
/ 05 декабря 2018

У меня есть запрос, который покажет последние 3 зарплаты в течение 2-летнего периода (если их три). У меня есть запрос, и проблема в том, является ли он очень медленным ... Мне интересно, было лилучший способ написать этот запрос.Я кое-что новое для оракула.

Вот мои таблицы

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     |

Наши даты окончания по умолчанию - 31.12.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 голосов
/ 05 декабря 2018

Упрощенная форма:

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 столбца для недавнего, старшего и самого старого оклада на человека

...