See The Employee Salary Amount on a Given Date

Asked

Viewed 1,312 times

4

Does anyone know what a query would look like to see what a certain employee’s salary is at a certain date?

The table of the salary adjustment history of each employee has the following fields:

inserir a descrição da imagem aqui

MATRICULA DATA    SALARIO_ANTERIOR    REAJUSTE    NOME    ADMISSAO_DATA   SALARIO_FIXO
000283  01.08.2009  4729.59 270.53  FULANO DA SILVA 13.07.2009  5982.48
000283  01.07.2010  5000.12 274.51  FULANO DA SILVA 13.07.2009  5982.48
000283  01.08.2011  5274.63 369.22  FULANO DA SILVA 13.07.2009  5982.48
000283  01.08.2012  5643.85 338.63  FULANO DA SILVA 13.07.2009  5982.48

The ADMISSAO_DATA and SALARIO_FIXO fields are from the Employees table I made a Join between the Readjustment Histories tables with Employees where generated the above result. The SALARIO_FIXO field is from the Employees table where you always store the current salary after the last adjustment. In the above result is 5982.48 after the adjustment made on 01.08.2012 which previously was 5643.85.

How would I consult, for example what was the salary value of this employee enrollment 000283 on 01.05.2012? I could not develop a query to check and compare to see how much the salary was on this desired date.

Can someone help me?


Sorack, it’s all right?

I passed this query to Mysql Bank but the last query record cannot calculate the value of the current salary after the last adjustment. It looks exactly like this in the image below, arrow the initial value before the readjustment and the date is set the first date before the readjustment, but when the query runs in SQL Fiddle correctly.

inserir a descrição da imagem aqui

The right result should come out like this:

inserir a descrição da imagem aqui

  • The query made by me is like this: SELECT fr.matricula, fr.data, fr.salario_anterior, fr.reajuste, f.nome, f.admissao_data, f.salario_fixo
FROM funcionarios_reajustes fr
JOIN funcionarios AS f ON (f.matricula = fr.matricula)
WHERE tr.matricula = 00283
ORDER BY f.nome, fr.data ASC

  • You can add one more filter in WHERE by filtering only the date. SELECT fr.matricula, 
fr.data, 
fr.salario_anterior, 
fr.reajuste, 
f.nome, 
f.admissao_data, 
f.salario_fixo 
FROM funcionarios_reajustes fr 
JOIN funcionarios AS f 
 ON (f.matricula = fr.matricula) 
 WHERE tr.matricula = 00283 
 AND fr.data BETWEEN '20120501 00:00:00' and '20120501 23:59:59'
 ORDER BY f.nome, fr.data ASC

  • The other select to select on a given date looks like this: SELECT&#xA; CASE&#xA; WHEN '01.08.2009' < data THEN salario_anterior&#xA; WHEN '01.07.2010' < data THEN salario_anterior&#xA; WHEN '01.08.2011' < data THEN salario_anterior&#xA; WHEN '01.08.2012' < data THEN salario_anterior&#xA; END AS salario&#xA;FROM (SELECT fr.matricula, fr.data, fr.salario_anterior, fr.reajuste, f.nome, f.admissao_data, f.salario_fixo&#xA;FROM funcionarios_reajustes fr&#xA;JOIN funcionarios AS t ON (f.matricula = fr.matricula))&#xA;WHERE matricula = 00283 AND data = '01.05.2012'

  • @Jorgitodasilvapaiva made an edit in my reply to fix problems with respect to multiple registrations. Please check.

1 answer

3


Its whole problem is because the tables seem to be modeled in a way too complicated for the problem that must be solved. I suggest that, if possible, a table be created salario that has the value, beginning of the duration and value of the salary, so the problem will be easily solved. If you cannot change the structure, use the following query to extract the expected values:

SELECT x.matricula,
       x.tipo,
       x.salario,
       x.de,
       x.ate,
       x.reajuste
  FROM (-- Pega apenas os primeiros salários
        SELECT y1.*
          FROM (SELECT 'Contratação' AS tipo,
                       -- Caso ainda não possua reajuste utiliza a data atual como referência de final
                       COALESCE(DATE_SUB(fr.data, INTERVAL 1 DAY), CURDATE()) AS ate,
                       f.admissao_data AS de,
                       -- Caso não possua registro de reajuste utiliza o salario_fixo
                       COALESCE(fr.salario_anterior, f.salario_fixo) AS salario,
                       NULL AS salario_anterior,
                       NULL AS reajuste,
                       f.matricula
                  FROM funcionarios f
                       -- LEFT para caso seja o primeiro salário do funcionário
                       LEFT JOIN funcionarios_reajustes fr ON fr.matricula = f.matricula
                 -- Pega apenas os registros que não possuam anterior (primeiros)
                 WHERE NOT EXISTS(SELECT 1
                                    FROM funcionarios_reajustes fr2
                                   WHERE fr2.matricula = f.matricula
                                     AND fr2.data < fr.data)
                 ORDER BY fr.data) y1
         UNION
        -- Demais salários
        SELECT y2.*
          FROM (SELECT 'Reajuste' AS tipo,
                       CASE @matricula
                         -- Se não for o último utiliza a data do próximo reajuste menos 1 dia
                         WHEN fr.matricula THEN DATE_SUB(@data_proximo, INTERVAL 1 DAY)
                         -- Se for o último utiliza a data atual para referência de valor final
                         ELSE CURDATE()
                       END AS ate,
                       @data_proximo := fr.data AS de,
                       CASE @matricula
                         -- Se não for o último utiliza o valor do próximo reajuste
                         WHEN fr.matricula THEN @salario_anterior
                         -- Se for o último faz o cálculo
                         ELSE fr.salario_anterior + fr.reajuste
                       END AS salario,
                       @salario_anterior := fr.salario_anterior AS salario_anterior,
                       fr.reajuste,
                       @matricula := fr.matricula AS matricula
                  FROM funcionarios_reajustes fr
                 ORDER BY fr.matricula, fr.data DESC) y2
         ) x
 WHERE x.matricula = '000283'
   AND STR_TO_DATE('15/07/2011', '%d/%m/%Y') BETWEEN x.de AND x.ate
 ORDER BY x.matricula,
          x.de

The previous query:

  • Take the value of the oldest record to know which employee’s first salary;
  • Merge the record with the calculated ones;
  • Gather the data ordered by the newest dates first;
  • Uses control variables that are filled in the previous record (i.e., newer). Thus the current salary is filled and the effective date;
  • In the result set the filter is performed by the desired date.

Observing: I suggest you create a VIEW with the query above to facilitate legibility and re-use.


See working on SQL Fiddle.


If you want to follow the direction of creating another table, the suggestion would be the following:

CREATE TABLE IF NOT EXISTS salario(
  codigo    INT AUTO_INCREMENT,
  matricula VARCHAR(6),
  salario   DECIMAL(15, 2),
  inicio    DATE,
  CONSTRAINT pk_salario PRIMARY KEY(codigo),
  CONSTRAINT fk_salario_funcionarios FOREIGN KEY(matricula) REFERENCES funcionarios(matricula)
);

And for popular:

INSERT INTO salario(matricula,
                    salario,
                    inicio)
SELECT x.matricula,
       x.salario,
       x.de
  FROM (-- Pega apenas os primeiros salários
        SELECT y1.*
          FROM (SELECT 'Contratação' AS tipo,
                       -- Caso ainda não possua reajuste utiliza a data atual como referência de final
                       COALESCE(DATE_SUB(fr.data, INTERVAL 1 DAY), CURDATE()) AS ate,
                       f.admissao_data AS de,
                       -- Caso não possua registro de reajuste utiliza o salario_fixo
                       COALESCE(fr.salario_anterior, f.salario_fixo) AS salario,
                       NULL AS salario_anterior,
                       NULL AS reajuste,
                       f.matricula
                  FROM funcionarios f
                       -- LEFT para caso seja o primeiro salário do funcionário
                       LEFT JOIN funcionarios_reajustes fr ON fr.matricula = f.matricula
                 -- Pega apenas os registros que não possuam anterior (primeiros)
                 WHERE NOT EXISTS(SELECT 1
                                    FROM funcionarios_reajustes fr2
                                   WHERE fr2.matricula = f.matricula
                                     AND fr2.data < fr.data)
                 ORDER BY fr.data) y1
         UNION
        -- Demais salários
        SELECT y2.*
          FROM (SELECT 'Reajuste' AS tipo,
                       CASE @matricula
                         -- Se não for o último utiliza a data do próximo reajuste menos 1 dia
                         WHEN fr.matricula THEN DATE_SUB(@data_proximo, INTERVAL 1 DAY)
                         -- Se for o último utiliza a data atual para referência de valor final
                         ELSE CURDATE()
                       END AS ate,
                       @data_proximo := fr.data AS de,
                       CASE @matricula
                         -- Se não for o último utiliza o valor do próximo reajuste
                         WHEN fr.matricula THEN @salario_anterior
                         -- Se for o último faz o cálculo
                         ELSE fr.salario_anterior + fr.reajuste
                       END AS salario,
                       @salario_anterior := fr.salario_anterior AS salario_anterior,
                       fr.reajuste,
                       @matricula := fr.matricula AS matricula
                  FROM funcionarios_reajustes fr
                 ORDER BY fr.matricula, fr.data DESC) y2
         ) x
 WHERE x.matricula = '000283'
   AND STR_TO_DATE('15/07/2011', '%d/%m/%Y') BETWEEN x.de AND x.ate
 ORDER BY x.matricula,
          x.de
  • Sorack, but the result was not what was expected, because look at the consultation was what was the salary on 07/15/2011, right? Then the value should be 5274.63 because this was the value before the adjustment made in 01/08/2011. The result is showing the amount of the salary after the adjustment, in case the amount of 5643.85.

  • Perfect Sorack, but if you wish to know the value before the first adjustment in the case before 01/08/2009, for example put the date 13/09/2009 when the employee was hired and the initial salary 4729.59

  • OK @Sorack I look forward to that, thanks in advance for your help.

  • I thank you very much for your help, thank you very much for your willingness, I will study this sql well to understand right, I did not remember this function COALESCE. Thank you very much!!!!!!

  • Sorack should insert a comment accepting the answer as correct?

  • Sorack, are you okay? I passed this query to Mysql Bank but the last query record cannot calculate the value of the current salary after the last adjustment. It looks exactly like this: 4729.59 2009-07-13 2009-07-31 5000.12 2009-08-01 2010-06-30 270.53 5274.63 2010-07-01 2011-07-31 274.51&#xA;5643.85 2011-08-01 2012-07-31 369.22&#xA;4729.59 2012-08-01 2009-07-31 338.63 ???

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.