tags:

views:

43

answers:

3

I have a table in SqlServer 2008 with data of the form

UserID  StartWeek  EndWeek   Type
1       1          3         A
1       4          5         A
1       6          10        A
1       11         13        B
1       14         16        A
2       1          5         A
2       6          9         A
2       10         16        B

I'd like to consolidate/condense the adjacent types so that the resulting table looks like this.

UserID  StartWeek  EndWeek   Type
1       1          10        A
1       11         13        B
1       14         16        A
2       1          9         A
2       10         16        B

Does anyone have any suggestions as to the best way to accomplish this? I've been looking at using Row_number and Partition, but I can't get it to behave exactly as I'd like.

+1  A: 

There's probably a neater way to do it, but this produces the correct result

DECLARE @t TABLE
(UserId TINYINT
,StartWeek TINYINT
,EndWeek TINYINT
,TYPE CHAR(1)
)

INSERT @t
      SELECT 1,1,3,'A'
UNION SELECT 1,4,5,'A'
UNION SELECT 1,6,10,'A'
UNION SELECT 1,11,13,'B'
UNION SELECT 1,14,16,'A'
UNION SELECT 2,1,5,'A'
UNION SELECT 2,6,9,'A'
UNION SELECT 2,10,16,'B'

;WITH srcCTE
AS
(
        SELECT *
               ,ROW_NUMBER() OVER (PARTITION BY t1.UserID, t1.Type
                                   ORDER BY t1.EndWeek
                                   ) AS rn 
        FROM @t AS t1
)
,recCTE
AS
(
        SELECT *
               ,0 AS grp
        FROM srcCTE
        WHERE rn = 1

        UNION ALL

        SELECT s.UserId
               ,s.StartWeek
               ,s.EndWeek 
               ,s.TYPE 
               ,s.rn
               ,CASE WHEN s.StartWeek - 1 = r.EndWeek
                     THEN r.grp 
                     ELSE r.grp+ 1
                END AS GRP
        FROM srcCTE AS s
        JOIN recCTE AS r
        ON   r.UserId = s.UserId
        AND  r.TYPE   = s.TYPE
        AND  r.rn     = s.rn - 1
)
SELECT UserId
       ,MIN(StartWeek) AS StartWeek
       ,MAX(EndWeek)   AS EndWeek
       ,TYPE
FROM recCTE AS s1
GROUP BY UserId
         ,TYPE
         ,grp
Ed Harper
Cheers, it may not look as elegant as the other solution, but it'll be easier to understand, both for myself and my other team-mates.
Stark
+1  A: 

Also using a CTE, but in a slightly different way

DECLARE @Consolidate TABLE (
  UserID INTEGER, StartWeek INTEGER, 
  EndWeek INTEGER, Type CHAR(1))

INSERT INTO @Consolidate VALUES (1, 1, 3, 'A')
INSERT INTO @Consolidate VALUES (1, 4, 5, 'A')
INSERT INTO @Consolidate VALUES (1, 6, 10, 'A')
INSERT INTO @Consolidate VALUES (1, 14, 16, 'A')
INSERT INTO @Consolidate VALUES (1, 11, 13, 'B')
INSERT INTO @Consolidate VALUES (2, 1, 5, 'A')
INSERT INTO @Consolidate VALUES (2, 6, 9, 'A')
INSERT INTO @Consolidate VALUES (2, 10, 16, 'B')

;WITH ConsolidateCTE AS 
(
  SELECT  UserID, StartWeek, EndWeek, Type
  FROM    @Consolidate
  UNION ALL 
  SELECT  cte.UserID, cte.StartWeek, c.EndWeek, c.Type
  FROM    ConsolidateCTE cte 
          INNER JOIN @Consolidate c ON 
            c.UserID = cte.UserID
            AND c.StartWeek = cte.EndWeek + 1
            AND c.Type = cte.Type
)
SELECT  UserID, [StartWeek] = MIN(Startweek), EndWeek, Type
FROM    (
          SELECT  UserID, Startweek, [EndWeek] = MAX(EndWeek), Type
          FROM    ConsolidateCTE
          GROUP BY  UserID, StartWeek, Type
        ) c
GROUP BY  UserID, EndWeek, Type
ORDER BY 1, 2, 3
Lieven
A: 

It is a really good puzzle! I tried to cover different solutions in my blog. http://burnall.livejournal.com/6962.html#cutid1

I hope it helps!