Select past 3 dates and determine if the 1st and 3rd are within a timeframe

  • Hi all,

    I have a table with addresses and activity dates. I need to be able to retrieve the past 3 activity dates and see if the first and last occured within 15 days. If so, I need to flag them.

    I'm not quite sure where to start. Using max date gets me the last date but not the previous two. I was trying to use top 3 in desc order and that didnt seem to work either.

    Any help would be appreciated...thanks!

  • Not enough to really provide you with code as nothing to work with. I would use a CTE and the row_number() over (partition by ... order by ... desc) to be able to identify the latest 3 dates.

    If you want more you'll need to post DDL (CREATE TABLE statement) for the table(s) involved, some sample data for the table(s) in the form os INSERT INTO statements, and the expected results based on the sample data. For assistance in all this, please read the first article I have linked below in my signature block. It will walk you through what you should post and how to do it.

  • Here is an example code demonstrating a method but not a solution. For a full solution, follow Lynn's advice on supplying further information.

    😎

    USE tempdb;

    GO

    ;WITH SAMPLE_DATA(ACTIVITY_DATE) AS

    (SELECT ACTIVITY_DATE FROM (VALUES

    ('2014-02-27 00:15:45.000')

    ,('2014-02-28 18:52:29.000')

    ,('2014-02-28 21:05:56.000')

    ,('2014-03-01 21:45:19.000')

    ,('2014-03-03 02:34:01.000')

    ,('2014-03-04 19:47:02.000')

    ,('2014-03-05 12:10:45.000')

    ,('2014-03-14 10:43:06.000')

    ,('2014-03-14 12:45:34.000')

    ,('2014-03-15 18:24:42.000')

    ,('2014-03-21 17:40:39.000')

    ,('2014-03-31 09:18:04.000')) AS X(ACTIVITY_DATE)

    )

    ,QUERY_BASE AS

    (

    SELECT

    ROW_NUMBER() OVER

    (

    ORDER BY SD.ACTIVITY_DATE DESC

    ) AS AD_RID

    ,SD.ACTIVITY_DATE

    FROM SAMPLE_DATA SD

    )

    SELECT

    QB.AD_RID

    ,QB.ACTIVITY_DATE

    ,DATEDIFF(HOUR,QB.ACTIVITY_DATE,MAX(QB.ACTIVITY_DATE) OVER (PARTITION BY (SELECT NULL))) / 24 AS PeriodInDays

    FROM QUERY_BASE QB

    WHERE QB.AD_RID <= 3;

    Results

    AD_RID ACTIVITY_DATE PeriodInDays

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

    1 2014-03-31 09:18:04.000 0

    2 2014-03-21 17:40:39.000 9

    3 2014-03-15 18:24:42.000 15

  • Thanks for responding Lynn! Below is a small test case.

    CREATE TABLE [dbo].[ActivityTable](

    [CompanyId] [int] NULL,

    [CompanyName] [varchar](20) NULL,

    [ActivityDate] [date] NULL

    ) ON [PRIMARY]

    GO

    insert into ActivityTable values(1,'ABC','2014-08-01')

    insert into ActivityTable values(1,'ABC','2014-08-03')

    insert into ActivityTable values(1,'ABC','2014-08-10')

    insert into ActivityTable values(1,'ABC','2014-07-20')

    insert into ActivityTable values(2,'AJAX','2014-08-01')

    insert into ActivityTable values(2,'AJAX','2014-08-10')

    insert into ActivityTable values(2,'AJAX','2014-05-10')

    insert into ActivityTable values(2,'AJAX','2014-05-20')

    insert into ActivityTable values(3,'TURNER','2014-07-01')

    insert into ActivityTable values(3,'TURNER','2014-07-31')

    insert into ActivityTable values(3,'TURNER','2014-06-15')

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

    I'm looking for the last three dates for each company and if those three dates are within 15 days.

    In the above example, the ABC company would be returned.

    Thanks!

  • caoneill (9/7/2014)


    Thanks for responding Lynn! Below is a small test case.

    CREATE TABLE [dbo].[ActivityTable](

    [CompanyId] [int] NULL,

    [CompanyName] [varchar](20) NULL,

    [ActivityDate] [date] NULL

    ) ON [PRIMARY]

    GO

    insert into ActivityTable values(1,'ABC','2014-08-01')

    insert into ActivityTable values(1,'ABC','2014-08-03')

    insert into ActivityTable values(1,'ABC','2014-08-10')

    insert into ActivityTable values(1,'ABC','2014-07-20')

    insert into ActivityTable values(2,'AJAX','2014-08-01')

    insert into ActivityTable values(2,'AJAX','2014-08-10')

    insert into ActivityTable values(2,'AJAX','2014-05-10')

    insert into ActivityTable values(2,'AJAX','2014-05-20')

    insert into ActivityTable values(3,'TURNER','2014-07-01')

    insert into ActivityTable values(3,'TURNER','2014-07-31')

    insert into ActivityTable values(3,'TURNER','2014-06-15')

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

    I'm looking for the last three dates for each company and if those three dates are within 15 days.

    In the above example, the ABC company would be returned.

    Thanks!

    Just curious, what if you only have 2 activity dates for a company?

  • Hi Lynn,

    If there are only 2 then it's just ignored. Three is the magic number! 🙂

  • Try this:

    CREATE TABLE [dbo].[ActivityTable](

    [CompanyId] [int] NULL,

    [CompanyName] [varchar](20) NULL,

    [ActivityDate] [date] NULL

    ) ON [PRIMARY]

    GO

    insert into ActivityTable values(1,'ABC','2014-08-01')

    insert into ActivityTable values(1,'ABC','2014-08-03')

    insert into ActivityTable values(1,'ABC','2014-08-10')

    insert into ActivityTable values(1,'ABC','2014-07-20')

    insert into ActivityTable values(2,'AJAX','2014-08-01')

    insert into ActivityTable values(2,'AJAX','2014-08-10')

    insert into ActivityTable values(2,'AJAX','2014-05-10')

    insert into ActivityTable values(2,'AJAX','2014-05-20')

    insert into ActivityTable values(3,'TURNER','2014-07-01')

    insert into ActivityTable values(3,'TURNER','2014-07-31')

    insert into ActivityTable values(3,'TURNER','2014-06-15')

    insert into ActivityTable values(4,'TURNER-2','2014-07-01')

    insert into ActivityTable values(4,'TURNER-2','2014-07-10')

    go

    with BaseData as (

    select

    CompanyId,

    CompanyName,

    ActivityDate,

    rn = row_number() over (partition by CompanyId order by ActivityDate desc),

    cnt = count(*) over (partition by CompanyId)

    from

    dbo.ActivityTable

    ), InterimData as (

    select

    CompanyId,

    CompanyName,

    min(ActivityDate) MinDate,

    max(ActivityDate) MaxDate

    from

    BaseData

    where

    rn <= 3 and

    cnt > 2

    group by

    CompanyId,

    CompanyName

    )

    select

    CompanyName

    from

    InterimData

    where

    datediff(day,MinDate,MaxDate) <= 15;

    go

    DROP TABLE [dbo].[ActivityTable];

    go

  • Here's a different approach.

    WITH MinDates AS(

    SELECT CompanyId,

    DATEADD( dd, -15, MAX(ActivityDate)) MinDate

    FROM ActivityTable

    GROUP BY CompanyId

    )

    SELECT a.CompanyId,

    a.CompanyName

    FROM ActivityTable a

    JOIN MinDates m ON a.CompanyId = m.CompanyId

    AND a.ActivityDate > m.MinDate

    GROUP BY a.CompanyId,

    a.CompanyName

    HAVING COUNT(*) >= 3;

    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 posted solution seems to do the trick...thanks so much!

  • Luis Cazares (9/7/2014)


    Here's a different approach.

    WITH MinDates AS(

    SELECT CompanyId,

    DATEADD( dd, -15, MAX(ActivityDate)) MinDate

    FROM ActivityTable

    GROUP BY CompanyId

    )

    SELECT a.CompanyId,

    a.CompanyName

    FROM ActivityTable a

    JOIN MinDates m ON a.CompanyId = m.CompanyId

    AND a.ActivityDate > m.MinDate

    GROUP BY a.CompanyId,

    a.CompanyName

    HAVING COUNT(*) >= 3;

    Where do you capture the three most recent dates?

  • I don't. I just validate that there are at least 3 dates within the range. This works if the dates aren't important and you just want to know the companies.

    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
  • Luis Cazares (9/7/2014)


    I don't. I just validate that there are at least 3 dates within the range. This works if the dates aren't important and you just want to know the companies.

    From the OPs initial post:

    I need to be able to retrieve the past 3 activity dates and see if the first and last occured within 15 days.

  • For completeness, here is a complete solution to the problem using the method I posted earlier and the sample data set posted.

    😎

    ;WITH QUERY_BASE AS

    (

    SELECT

    ROW_NUMBER() OVER

    (

    PARTITION BY SD.CompanyId

    ORDER BY SD.ActivityDate DESC

    ) AS AD_RID

    ,SD.CompanyId

    ,SD.CompanyName

    ,SD.ActivityDate

    FROM ActivityTable SD

    )

    ,FINAL_SET AS

    (

    SELECT

    QB.AD_RID

    ,QB.CompanyId

    ,QB.CompanyName

    ,QB.ActivityDate

    ,DATEDIFF(HOUR,QB.ActivityDate,MAX(QB.ActivityDate) OVER (PARTITION BY QB.CompanyId)) / 24 AS PeriodInDays

    FROM QUERY_BASE QB

    WHERE QB.AD_RID <= 3

    )

    SELECT

    FS.AD_RID

    ,FS.CompanyId

    ,FS.CompanyName

    ,FS.ActivityDate

    ,FS.PeriodInDays

    FROM FINAL_SET FS

    WHERE FS.AD_RID = 3

    AND FS.PeriodInDays >= 15

    Results

    AD_RID CompanyId CompanyName ActivityDate PeriodInDays

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

    3 2 AJAX 2014-05-20 82

    3 3 TURNER 2014-06-15 46

  • Eirikur Eiriksson (9/7/2014)


    For completeness, here is a complete solution to the problem using the method I posted earlier and the sample data set posted.

    😎

    ;WITH QUERY_BASE AS

    (

    SELECT

    ROW_NUMBER() OVER

    (

    PARTITION BY SD.CompanyId

    ORDER BY SD.ActivityDate DESC

    ) AS AD_RID

    ,SD.CompanyId

    ,SD.CompanyName

    ,SD.ActivityDate

    FROM ActivityTable SD

    )

    ,FINAL_SET AS

    (

    SELECT

    QB.AD_RID

    ,QB.CompanyId

    ,QB.CompanyName

    ,QB.ActivityDate

    ,DATEDIFF(HOUR,QB.ActivityDate,MAX(QB.ActivityDate) OVER (PARTITION BY QB.CompanyId)) / 24 AS PeriodInDays

    FROM QUERY_BASE QB

    WHERE QB.AD_RID <= 3

    )

    SELECT

    FS.AD_RID

    ,FS.CompanyId

    ,FS.CompanyName

    ,FS.ActivityDate

    ,FS.PeriodInDays

    FROM FINAL_SET FS

    WHERE FS.AD_RID = 3

    AND FS.PeriodInDays >= 15

    Results

    AD_RID CompanyId CompanyName ActivityDate PeriodInDays

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

    3 2 AJAX 2014-05-20 82

    3 3 TURNER 2014-06-15 46

    Unfortunately, Eirikur, your solution does not return the correct result set as per the OPs requirement. The only company that should be returned from the sample data is ABC.

    Look at the 1st and 3rd activity dates, only if the difference between these dates is 15 days or later do you return a result. If there are fewer than 3 records you also ignore that company.

  • Ooops, greater than is stead of less than in the last filter:pinch: Misread the post as "where three last activities are in a period greater or equal to 15 days"

    😎

    USE tempdb;

    GO

    ;WITH QUERY_BASE AS

    (

    SELECT

    ROW_NUMBER() OVER

    (

    PARTITION BY SD.CompanyId

    ORDER BY SD.ActivityDate DESC

    ) AS AD_RID

    ,SD.CompanyId

    ,SD.CompanyName

    ,SD.ActivityDate

    FROM ActivityTable SD

    )

    ,FINAL_SET AS

    (

    SELECT

    QB.AD_RID

    ,QB.CompanyId

    ,QB.CompanyName

    ,QB.ActivityDate

    ,DATEDIFF(HOUR,QB.ActivityDate,MAX(QB.ActivityDate) OVER (PARTITION BY QB.CompanyId)) / 24 AS PeriodInDays

    FROM QUERY_BASE QB

    WHERE QB.AD_RID <= 3

    )

    SELECT

    FS.AD_RID

    ,FS.CompanyId

    ,FS.CompanyName

    ,FS.ActivityDate

    ,FS.PeriodInDays

    FROM FINAL_SET FS

    WHERE FS.AD_RID = 3

    AND FS.PeriodInDays <= 15

    Results

    AD_RID CompanyId CompanyName ActivityDate PeriodInDays

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

    3 1 ABC 2014-08-01 9

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

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