Bogusz Michałowski
Bogusz Michałowski

Reputation: 342

Aggregate within a group of unchanged values

I have sample data:

RowId TypeId Value
    1      1    34
    2      1    53
    3      1    34
    4      2    43
    5      2    65
    6     16    54
    7     16    34
    8      1    45
    9      6    43
   10      6    34
   11     16    64
   12     16    63

I want to count row for each type (The Value does not matter to me), but only for... neighbor TypeId

TypeId Count
     1     3
     2     2 
    16     2
     1     1
     6     2
    16     2

How to achieve this result?

Upvotes: 3

Views: 117

Answers (2)

Bulat
Bulat

Reputation: 6979

This should give you COUNT of rows within a group of unchanged values:

SELECT TypeId, grp, COUNT(*) FROM (
  SELECT RowId, TypeId , Value, gap, SUM(gap) over (ORDER BY RowId ) grp
  FROM (SELECT RowId, TypeId , Value,
                CASE WHEN TypeId = lag(TypeId) over (ORDER BY RowId )
                   THEN 0
                   ELSE 1
                END gap 
        FROM dummy
    ) t
) tt
GROUP BY TypeId, grp;

If you prefer WITH over endless sub-query inclusions:

WITH dummy_with_groups AS (
  SELECT RowId, TypeId , Value, SUM(gap) OVER (ORDER BY RowId) grp
  FROM (SELECT RowId, TypeId , Value,
          CASE WHEN TypeId = lag(TypeId) OVER (ORDER BY RowId)
          THEN 0 ELSE 1 END gap 
        FROM dummy) t
)
SELECT TypeId, COUNT(*) as Result 
FROM dummy_with_groups
GROUP BY TypeId, grp;

http://www.sqlfiddle.com/#!6/f16e9/34

Upvotes: 4

Rachcha
Rachcha

Reputation: 8816

Check this fiddle demo. I have renamed your columns a little.

WITH myCTE AS
         (SELECT row_id,
                 type_id,
                 ROW_NUMBER () OVER (PARTITION BY type_id ORDER BY row_id)
                     AS cnt,
                 CASE LEAD (type_id) OVER (ORDER BY row_id)
                     WHEN type_id THEN 0
                     ELSE 1
                 END
                     AS show
            FROM dummy),
     innerQuery AS
         (SELECT row_id, type_id, cnt
            FROM myCTE
           WHERE show = 1)
SELECT iq1.type_id, iq1.cnt - ISNULL (iq2.cnt, 0) CNT
  FROM innerQuery iq1
       LEFT OUTER JOIN innerQuery iq2
           ON     iq1.type_id = iq2.type_id
              AND EXISTS
                      (SELECT 1
                         FROM innerQuery iq3
                        WHERE     iq3.type_id = iq1.type_id
                              AND iq3.row_id < iq1.row_id
                       HAVING MAX (iq3.row_id) = iq2.row_id)

The output is exactly as expected.

Upvotes: 3

Related Questions