SQL Grouping Min and Max dates on a field that changes

Hi

I have a table which contains a list of dates and each date has a code. I want to be able to group each code by the start and end date for each interval because the codes can be repeated.

Eg from the output below I want to end up with:
01D 05/09/15 - 09/09/15
00T 10/09/15 - 12/09/15
01D 13/09/15 - 16/09/15
etc...

Date      Org_Code
2015-09-05 00:00:00.000      01D
2015-09-06 00:00:00.000      01D
2015-09-07 00:00:00.000      01D
2015-09-08 00:00:00.000      01D
2015-09-09 00:00:00.000      01D
2015-09-10 00:00:00.000      00T
2015-09-11 00:00:00.000      00T
2015-09-12 00:00:00.000      00T
2015-09-13 00:00:00.000      01D
2015-09-14 00:00:00.000      01D
2015-09-15 00:00:00.000      01D
2015-09-16 00:00:00.000      01D
2015-09-17 00:00:00.000      00T
2015-09-18 00:00:00.000      01D
2015-09-19 00:00:00.000      01D
karlchad1Asked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Vikas GargAssociate Principal EngineerCommented:
HI,

You can use Min , Max function for the same



SELECT ORG_CODE,MIN(DATE,MAX(DATE)
FROM
(
Select org_code, date,ROW_NUMBER()over(partition by org_code order by date) rn
from 
Table 
)
group by org_code,RN

Open in new window

karlchad1Author Commented:
This doesn't split out each interval, it groups the data to return 2 records instead of a new record for each change in Code (ie 5).
ste5anSenior DeveloperCommented:
It's simple in SQL 2012+:

DECLARE @Sample TABLE
    (
      [Date] DATE ,
      Org_Code CHAR(3)
    );

INSERT  INTO @Sample
VALUES  ( '2015-09-05', '01D' ),
        ( '2015-09-06', '01D' ),
        ( '2015-09-07', '01D' ),
        ( '2015-09-08', '01D' ),
        ( '2015-09-09', '01D' ),
        ( '2015-09-10', '00T' ),
        ( '2015-09-11', '00T' ),
        ( '2015-09-12', '00T' ),
        ( '2015-09-13', '01D' ),
        ( '2015-09-14', '01D' ),
        ( '2015-09-15', '01D' ),
        ( '2015-09-16', '01D' ),
        ( '2015-09-17', '00T' ),
        ( '2015-09-18', '01D' ),
        ( '2015-09-19', '01D' );
		
WITH    IntervallStart
          AS ( SELECT   * ,
                        IIF(LAG(Org_Code, 1, 'XXXX') OVER ( ORDER BY [Date] ) != Org_Code, 1, 0) AS IntervallStart
               FROM     @Sample
             ),
        IntervallNumber
          AS ( SELECT   * ,
                        SUM(IntervallStart) OVER ( ORDER BY [Date] ) AS IntervallNumber
               FROM     IntervallStart
             )
    SELECT  IntervallNumber ,
            Org_Code ,
            MIN([Date]) ,
            MAX([Date])
    FROM    IntervallNumber
    GROUP BY IntervallNumber ,
            IntervallNumber.Org_Code
    ORDER BY IntervallNumber;

Open in new window


In SQL Server 2008 you need a self-join over row_number() to replace the LAG() function.
ste5anSenior DeveloperCommented:
E.g.
DECLARE @Sample TABLE
    (
      [Date] DATE ,
      Org_Code CHAR(3)
    );

INSERT  INTO @Sample
VALUES  ( '2015-09-05', '01D' ),
        ( '2015-09-06', '01D' ),
        ( '2015-09-07', '01D' ),
        ( '2015-09-08', '01D' ),
        ( '2015-09-09', '01D' ),
        ( '2015-09-10', '00T' ),
        ( '2015-09-11', '00T' ),
        ( '2015-09-12', '00T' ),
        ( '2015-09-13', '01D' ),
        ( '2015-09-14', '01D' ),
        ( '2015-09-15', '01D' ),
        ( '2015-09-16', '01D' ),
        ( '2015-09-17', '00T' ),
        ( '2015-09-18', '01D' ),
        ( '2015-09-19', '01D' );
		
WITH    Numbered
          AS ( SELECT   * ,
                        ROW_NUMBER() OVER ( ORDER BY [Date] ) AS RN
               FROM     @Sample
             ),
        IntervallStart
          AS ( SELECT   L.* ,
                        CASE WHEN ISNULL(R.Org_Code, 'XXXX') <> L.Org_Code THEN 1
                             ELSE 0
                        END AS IntervallStart
               FROM     Numbered L
                        LEFT JOIN Numbered R ON R.RN = L.RN - 1
             ),
        IntervallNumber
          AS ( SELECT   * ,
                        SUM(IntervallStart) OVER ( ORDER BY [Date] ) AS IntervallNumber
               FROM     IntervallStart
             )
    SELECT  IntervallNumber ,
            Org_Code ,
            MIN([Date]) ,
            MAX([Date])
    FROM    IntervallNumber
    GROUP BY IntervallNumber ,
            IntervallNumber.Org_Code
    ORDER BY IntervallNumber;

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Vitor MontalvãoMSSQL Senior EngineerCommented:
karlchad1, do you still need help with this question?
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft SQL Server

From novice to tech pro — start learning today.