selecting max between two dates for a given year

  • I have three tables: EMP (ID, NAME), EMPDATE (ID, STARTDATE, ENDDATE), YEAR(YEAR)

    I would like to get the most recent date within a given year per each EMP?

    For example, EMPID 1 can be enrolled in many programs, each program has start end dates. I need to list the most recent date an employee was enrolled (max date between START AND END DATE which ever is most recent enrollment) for a given year. For example, for 2014 his/her most recent enrollment should be 10/23/2014 for year 2014 and 2013-10-24 for year 2013.

    SELECT ID, EMP.NAME, DTE.StartDate, DTE.ENDDATE, year

    FROM

    EMP_DATE DTE join

    EMP_INFO EMP on EMP.ID = DTE.ID join

    YEAR YR on YR.YEAR = YEAR(DTE.STARTDATE)

    DATA SAMPLE:

    EMP

    ID NAME

    1 JOHN

    EMP_INFO

    ID STARTDATE ENDDATE

    12013-10-24 2014-03-11

    12014-06-13 2014-03-11

    12014-06-15 2014-03-11

    12014-09-08 2014-03-11

    12014-09-12 2014-03-11

    12014-09-14 2014-03-11

    12014-01-13 2014-05-17

    12014-05-14 2014-06-09

    12014-06-10 2014-06-16

    12014-08-31 2014-09-04

    12014-09-05 2014-09-06

    12014-09-07 2014-10-23

    YEAR

    Year

    2012

    2013

    2014

    2015

  • You have been here long enough to know that you should post your data in a consumable format.

    The absence of evidence is not evidence of absence.
    Martin Rees

    You can lead a horse to water, but a pencil must be lead.
    Stan Laurel

  • Phil - I completely agree, I remember that and I appreciate it...

    Here is the script:

    Create table EMP

    (ID INT,

    NAME NVARCHAR(10)

    )

    insert into EMP values (1, 'JOHN')

    create table EMP_INFO

    (ID INT,

    STARTDATE DATE,

    ENDDATE DATE)

    insert into EMP_INFO values

    (1, '2013-10-24', '2014-03-11'),

    (1, '2014-06-13', '2014-03-11'),

    (1, '2014-06-15', '2014-03-11'),

    (1, '2014-09-08', '2014-03-11'),

    (1, '2014-09-12', '2014-03-11'),

    (1, '2014-09-14', '2014-03-11'),

    (1, '2014-01-13', '2014-05-17'),

    (1, '2014-05-14', '2014-06-09'),

    (1, '2014-06-10', '2014-06-16'),

    (1, '2014-08-31', '2014-09-04'),

    (1, '2014-09-05', '2014-09-06'),

    (1, '2014-09-07', '2014-10-23')

    create table [Year]

    ([year] numeric)

    insert into year values

    (2012),

    (2013),

    (2014),

    (2015)

  • lsalih (7/23/2015)


    Phil - I completely agree, I remember that and I appreciate it...

    Here is the script:

    Create table EMP

    (ID INT,

    NAME NVARCHAR(10)

    )

    insert into EMP values (1, 'JOHN')

    create table EMP_INFO

    (ID INT,

    STARTDATE DATE,

    ENDDATE DATE)

    insert into EMP_INFO values

    (1, '2013-10-24', '2014-03-11'),

    (1, '2014-06-13', '2014-03-11'),

    (1, '2014-06-15', '2014-03-11'),

    (1, '2014-09-08', '2014-03-11'),

    (1, '2014-09-12', '2014-03-11'),

    (1, '2014-09-14', '2014-03-11'),

    (1, '2014-01-13', '2014-05-17'),

    (1, '2014-05-14', '2014-06-09'),

    (1, '2014-06-10', '2014-06-16'),

    (1, '2014-08-31', '2014-09-04'),

    (1, '2014-09-05', '2014-09-06'),

    (1, '2014-09-07', '2014-10-23')

    create table [Year]

    ([year] numeric)

    insert into year values

    (2012),

    (2013),

    (2014),

    (2015)

    Can the ENDDATE be less than STARTDATE for any given row?

  • I fixed up your create table/insert scripts. No Semi-colons?

    use tempdb;

    go

    Create table EMP

    (ID INT,

    NAME NVARCHAR(10)

    );

    GO

    insert into EMP values (1, 'JOHN')

    create table EMP_INFO

    (ID INT,

    STARTDATE DATE,

    ENDDATE DATE);

    GO

    insert into EMP_INFO values

    (1, '2013-10-24', '2014-03-11'),

    (1, '2014-06-13', '2014-03-11'),

    (1, '2014-06-15', '2014-03-11'),

    (1, '2014-09-08', '2014-03-11'),

    (1, '2014-09-12', '2014-03-11'),

    (1, '2014-09-14', '2014-03-11'),

    (1, '2014-01-13', '2014-05-17'),

    (1, '2014-05-14', '2014-06-09'),

    (1, '2014-06-10', '2014-06-16'),

    (1, '2014-08-31', '2014-09-04'),

    (1, '2014-09-05', '2014-09-06'),

    (1, '2014-09-07', '2014-10-23');

    create table [Year]

    ([year] numeric)

    insert into year values

    (2012),

    (2013),

    (2014),

    (2015);

    GO

    What's the answer to this one? (Please post your expected answer.)

    Are you looking for the latest date between the StartDate and EndDate that's within a given year? (2012...2015?)

  • This seems to be what you're asking for. However, it seems awkward that you consider the enddate as an enrollment date.

    SELECT EMP.ID,

    EMP.NAME,

    MAX(x.EnrollmentDate) AS EnrollmentDate,

    YR.[year]

    FROM EMP_INFO DTE

    join EMP EMP on EMP.ID = DTE.ID

    CROSS APPLY (VALUES(DTE.StartDate),(DTE.EndDate)) x(EnrollmentDate)

    join [YEAR] YR on YR.[YEAR] = YEAR(x.EnrollmentDate)

    GROUP BY EMP.ID,

    EMP.NAME,

    YR.[year]

    Luis C.
    General Disclaimer:
    Are you seriously taking the advice and code from someone from the internet without testing it? Do you at least understand it? Or can it easily kill your server?

    How to post data/code on a forum to get the best help: Option 1 / Option 2
  • Lynn - the answer is yes.

  • Luis - Can you please tell me how you go about the max between start and end date?

  • lsalih (7/23/2015)


    Lynn - the answer is yes.

    Please explain how an ENDDATE can be less than the corresponding STARTDATE.

  • lsalih (7/23/2015)


    Luis - Can you please tell me how you go about the max between start and end date?

    I unpivoted the dates, so I wouldn't care which column has the date. That's why there's a CROSS APPLY between the JOINs.

    Read more about unpivoting using CROSS APPLY in here: http://www.sqlservercentral.com/articles/CROSS+APPLY+VALUES+UNPIVOT/91234/

    This won't give you the max between start and end date, but it will give you the results you requested.

    Luis C.
    General Disclaimer:
    Are you seriously taking the advice and code from someone from the internet without testing it? Do you at least understand it? Or can it easily kill your server?

    How to post data/code on a forum to get the best help: Option 1 / Option 2
  • Here's another approach:

    WITH cteEmpDates AS

    (

    SELECT ID, STARTDATE AS AnyDate FROM #EMP_INFO UNION ALL

    SELECT ID, ENDDATE FROM #EMP_INFO

    ), cteDates AS

    (

    SELECT DATEFROMPARTS([year],1,1) AS YearStartDate,

    DATEFROMPARTS([year],12,31) AS YearEndDate,

    [year]

    FROM #Year

    )

    SELECT t1.ID, t3.Name, t2.[year], MAX(t1.AnyDate) AS MaxDate

    FROM cteEmpDates t1

    JOIN cteDates t2 ON t1.AnyDate BETWEEN t2.YearStartDate AND t2.YearEndDate

    JOIN #Emp t3 ON t1.ID = t3.ID

    GROUP BY t1.ID, t3.Name, t2.[year];

    This returns:

    ID Name year MaxDate

    ----------- ---------- --------------------------------------- ----------

    1 JOHN 2013 2013-10-24

    1 JOHN 2014 2014-10-23

    DATEFROMPARTS was added in SQL2012. You can read more about it in the link for the book in my signature.

    Wayne
    Microsoft Certified Master: SQL Server 2008
    Author - SQL Server T-SQL Recipes


    If you can't explain to another person how the code that you're copying from the internet works, then DON'T USE IT on a production system! After all, you will be the one supporting it!
    Links:
    For better assistance in answering your questions
    Performance Problems
    Common date/time routines
    Understanding and Using APPLY Part 1 & Part 2

  • I will thank you, where EnrollmentDate is coming from?

  • Here's an alternate method: with only two columns, I'd probably skip using CROSS APPLY:

    DECLARE @starting_year int

    SET @starting_year = 2012

    SELECT subquery.ID, e.NAME, subquery.Year, subquery.Max_Date

    FROM (

    SELECT ID, Year, MAX(Date) AS Max_Date

    FROM EMP_INFO

    CROSS JOIN (

    SELECT 'Start' AS WhichDate UNION ALL

    SELECT 'End'

    ) AS WhichDate

    CROSS APPLY (

    SELECT CASE WHEN WhichDate = 'Start' THEN STARTDATE ELSE ENDDATE END AS Date

    ) AS aan1

    CROSS APPLY (

    SELECT YEAR(Date) AS Year

    ) AS aan2

    WHERE

    CASE WHEN WhichDate = 'Start' THEN STARTDATE ELSE ENDDATE END >= CAST(@starting_year AS char(4)) + '0101'

    GROUP BY ID, Year

    ) AS subquery

    INNER JOIN EMP e ON e.ID = subquery.ID

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • lsalih (7/23/2015)


    I will thank you, where EnrollmentDate is coming from?

    From this in the FROM clause:

    CROSS APPLY (VALUES(DTE.StartDate),(DTE.EndDate)) x(EnrollmentDate)

  • ScottPletcher (7/23/2015)


    Here's an alternate method: with only two columns, I'd probably skip using CROSS APPLY:

    DECLARE @starting_year int

    SET @starting_year = 2012

    SELECT subquery.ID, e.NAME, subquery.Year, subquery.Max_Date

    FROM (

    SELECT ID, Year, MAX(Date) AS Max_Date

    FROM EMP_INFO

    CROSS JOIN (

    SELECT 'Start' AS WhichDate UNION ALL

    SELECT 'End'

    ) AS WhichDate

    CROSS APPLY (

    SELECT CASE WHEN WhichDate = 'Start' THEN STARTDATE ELSE ENDDATE END AS Date

    ) AS aan1

    CROSS APPLY (

    SELECT YEAR(Date) AS Year

    ) AS aan2

    WHERE

    CASE WHEN WhichDate = 'Start' THEN STARTDATE ELSE ENDDATE END >= CAST(@starting_year AS char(4)) + '0101'

    GROUP BY ID, Year

    ) AS subquery

    INNER JOIN EMP e ON e.ID = subquery.ID

    So much work to do what Luis did in a very succinct piece of code.

Viewing 15 posts - 1 through 15 (of 23 total)

You must be logged in to reply to this topic. Login to reply