Question

I have a requirement to show a listing of data associated with a given widget, however I can only aggregate on the widget while it's in sequence (essentially breaking the running total when the widget changes).

Here's a bit of a break down of what I mean...

Example data:

ID    WIDGET    PART
1     A000      B22
2     A000      B23
3     A002      B24
4     A001      B25
5     A001      B26
6     A000      B27

Desired output:

WIDGET    MINPART    COUNT
A000      B22        2
A002      B24        1
A001      B25        2
A000      B27        1

In SQL Server I've tried running the following:

with a as (
select 
        WIDGET, 
        min(PART) over (partition by WIDGET) as MINPART, 
        1 tcount
from test ) 
select WIDGET, MINPART, sum(tcount)
from a
group by WIDGET, MINPART

But this just results in the usual aggregation you might expect. I.E.:

WIDGET    MINPART    COUNT
A000      B22        3
A002      B24        1
A001      B25        2
Was it helpful?

Solution

Does this work for you?

;with x as (
    select *,
    lag(widget) over(order by id) as lg
    from #t
),
y as (
    select *, sum(case when widget<>lg then 1 else 0 end) over(order by id) as grp
    from x
)
select widget, min(part), count(*)
from y
group by widget, grp

OTHER TIPS

Don't you mean to use the named columns?, i.e.

with a as (
select 
        WIDGET, 
        min(PART) over (partition by WIDGET) as MINPART, 
        1 tcount
from Widget ) 
select WIDGET, MINPART, sum(tcount)
from a
group by Widget, MinPart;

SqlFiddle here

we can write this one using derived table also other way

DECLARE @Widget  TABLE 
(ID INT,
Widget  NVARCHAR(10),
PART NVARCHAR(10));

INSERT INTO @Widget VALUES 
(1, 'A000', 'B22'),
(2, 'A000', 'B23'),
(3, 'A002', 'B24'),
(4, 'A001', 'B25'),
(5, 'A001', 'B26'),
(6, 'A000', 'B27');


IF OBJECT_ID('tempdb..#t1') IS NOT NULL
    DROP TABLE #t1
select  Widget,PART,1 as t into #t1  from
(select Widget,MIN(PART)OVER (PARTITION BY Widget) As Part from  @Widget
GROUP BY Widget,ID,PART)AS F

select Widget,PART,SUM(t)  from #t1
group by Widget, Part

@dean solution is neat but a pure SQLServer 2008 solution is possible, the idea is the same, the ranker formula

sum(case when widget<>lg then 1 else 0 end) over(order by id) as grp

can be faked by a running total, for the record the full query is

WITH part AS (
SELECT a.id, a.widget, a.part
     , breaker = CASE WHEN a.widget<>coalesce(b.widget, a.widget)
                      THEN 1
                      ELSE 0
                 END
FROM   Widgets a
       LEFT JOIN Widgets b ON a.id = b.id + 1
)
, DATA AS(
SELECT a.id, a.widget, a.part
     , rank = (SELECT sum(breaker) FROM part b WHERE a.id >=  b.id)
FROM   part a
)
SELECT widget
     , minpart = min(part)
     , [count] = count(1)
FROM DATA
GROUP BY widget, rank
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top