Share via

Combinación de dos tablas SQL con diferentes campos y teniendo en cuenta fechas

M_15 20 Reputation points
2023-10-25T08:41:13.0366667+00:00

Hello.

I have a problem with a SQL query (Server 2012):

From two tables I want to create another one (DisabilityHistory). One of them (DisabilityTypeHistory) contains the history of the type of disability of each person over time in a company and another (DisabilityPercentHistory) the percentage.

The "DisabilityTypeHistory" table contains the fields: Employee, StartCompanyDate (contract start date), EndCompanyDate (contract end date), StartDate (start date of that type of disability), EndDate (end date of that type of disability) and EmployeeType (type of disability) and the table "DisabilityPercentHistory": Employee, StartDate (start date of that degree of disability) and Degree (degree of the disability). "DisabilityPercentHistory" does not contain either the end of the section (end date of disability degree) and contract start and end dates.

It must be taken into account that a person may have been hired, leave the company, be hired again... In addition, one day the type of disability may have changed and not the percentage, or they may have changed both on the same day or only the percentage has changed. I need a new table (DisabilityHistory) in which all this information is stored, associating, for each date range, the type and degree of disability of each person.

It is necessary to take into account both the contract start and end dates and the start and end date of each "section".

For example, if we have the following data in both tables:

DisabilityTypeHistory:

Employee StartCompanyDate EndCompanyDate StartDate EndDate EmployeeType
1 01/07/1980 28/12/2022 01/07/1980 28/12/2022 SIN DISCAPACIDAD
1 02/01/2023 NULL 01/07/2023 NULL PDI

DisabilityPercentHistory:

StartDate Employee Degree
01/09/2022 1 33
02/01/2023 1 65

The resulting table (DisabilityHistory) should be:

Employee StartCompanyDate EndCompanyDate StartDate EndDate EmployeeType Degree
1 01/07/1980 28/12/2022 01/07/1980 31/08/2022 No disability NULL
1 01/07/1980 28/12/2022 01/09/2022 28/12/2022 No disability 33
1 02/01/2023 NULL 02/01/2023 30/06/2023 NULL 65
1 02/01/2023 NULL 01/07/2023 NULL PDI 65

Thank you!

SQL Server | Other
SQL Server | Other

Additional SQL Server features and topics not covered by specific categories


Answer accepted by question author

Erland Sommarskog 134.3K Reputation points MVP Volunteer Moderator
2023-10-28T21:31:46.84+00:00

Below is a query. Note also that I have added CREATE TABLE statements tables for your tables as well as INSERT statements with the sample data. We very much appreciate if you do this yourself, so that we, who are helping you in our free time, do not have to spend time on this. This time the amount of data was small, so I created this myself.

I also added a few more rows to the PercentHistory table, as I found it a little thin on test data.

Your description gave me some ideas of what the business rules are, but I had to make some extrapolations based on what I think is reasonable.

The solution uses a table of dates. You can learn about this concept in a short story on my web site, where you also find the script to create it: https://www.sommarskog.se/Short%20Stories/table-of-numbers.html#Dates Note that you will need to adjust the script, since you appears to havde dates before 1990.

The idea we use this table to produce a row for every day the employee has been employed. Then we retrieve the most recent start date for some disability and the most recent start date for a degree. When we compute two row_numbers. One is simply the date number for this employee's stint at the company, the other is the row number for a certain combo of disability and degree. The difference between these two numbers are the same as long as there are no changes. Then we can use MIN and MAX on the calendar date to get the start and end of the intervals.

 CREATE TABLE DisabilityTypeHistory(
       empid int NOT NULL,
       startcompanydate date NOT NULL,
       endcompanydate   date NULL,
       startdate        date NOT NULL,
       enddate          date NULL, 
       emptype          varchar(40) NULL, 
       PRIMARY KEY (empid, startcompanydate)
)
INSERT DisabilityTypeHistory 
   VALUES(1, '19800701', '20221228', '19800701', '20221228', 'No ailment'),
         (1, '20230201', NULL, '20230701',NULL, 'PDI')
go
CREATE TABLE DisabilityPercentHistory(
     empid int NOT NULL,
     startdate date NOT NULL,
     degree    int  NOT NULL,
     PRIMARY KEY (empid, startdate)
)
INSERT DisabilityPercentHistory
   VALUES(1, '20201111', 47),
         (1, '20220109', 33),
         (1, '20220117', 47),
         (1, '20230201', 65)

CREATE TABLE Employees (empid int NOT NULL PRIMARY KEY)
INSERT Employees(empid)
   VALUES(1)
go
; WITH DimSpan AS (
   SELECT TH.empid, TH.startcompanydate, TH.endcompanydate, d.d AS CalDate, 
          emptype = THsub.emptype, degree = isnull(PH.degree, 100), 
          grpno = row_number() OVER(PARTITION BY TH.empid, TH.startcompanydate ORDER BY d.d) -
                  row_number() OVER(PARTITION BY TH.empid, TH.startcompanydate, THsub.emptype, PH.degree ORDER BY d.d)
   FROM   (SELECT DISTINCT empid, startcompanydate, endcompanydate
           FROM   DisabilityTypeHistory) AS TH
   JOIN   Dates d ON d.d BETWEEN TH.startcompanydate AND isnull(TH.endcompanydate, dateadd(DAY, 1, convert(date, sysdatetime())))
   OUTER  APPLY (SELECT TOP (1) PH.degree
                 FROM   DisabilityPercentHistory PH
                 WHERE  PH.empid = TH.empid
                   AND  PH.startdate <= d.d
                 ORDER  BY PH.startdate DESC) AS PH
   OUTER APPLY (SELECT TOP (1) THsub.startdate, THsub.emptype
                FROM   DisabilityTypeHistory THsub
                WHERE  THsub.empid = TH.empid
                  AND  THsub.startcompanydate = TH.startcompanydate
                  AND  THsub.startdate <= d.d
                ORDER  BY THsub.startdate DESC) AS THsub
)
SELECT empid, startcompanydate, endcompanydate, MIN(CalDate), 
       nullif(MAX(CalDate), dateadd(DAY, 1, convert(date, sysdatetime()))), 
       emptype, degree, grpno
FROM   DimSpan 
GROUP  BY empid, startcompanydate, endcompanydate, emptype, degree, grpno
ORDER  BY empid, startcompanydate, MIN(CalDate)



SELECT * FROM DisabilityTypeHistory
SELECT * FROM DisabilityPercentHistory
go
DROP TABLE DisabilityPercentHistory
DROP TABLE DisabilityTypeHistory
DROP TABLE Employees

Was this answer helpful?

1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.