基于分组和顺序的总和

时间:2015-02-27 17:32:23

标签: sql-server tsql

我有类似下面的原始数据......

WO  OP  WC          Time
1   10  Band Saw    2.0
1   15  Band Saw    5.0
1   17  Band Saw    10.0
1   20  CNC Lathe   6.0
1   22  Band Saw    102.0
1   30  Inspection  33.0
2   10  Band Saw    1.5
2   20  CNC Lathe   6.00
2   20  CNC Lathe   2.00
2   30  CNC Punch   0.5
2   40  Manual Ops  1.25
2   50  Inspection  0.00

我需要它来汇总和分组如下。即将WO / WC柱的时间相加直到WC变化,而不是整个WO的总和。希望我已经足够清楚地解释了(可能没有) 我们需要支持SQL Server 2005。

WO  WC          Time
1   Band Saw    17.0
1   CNC Lathe   6.0
1   Band Saw    102.0
1   Inspection  33.0
2   Band Saw    1.5
2   CNC Lathe   8.00
2   CNC Punch   0.5
2   Manual Ops  1.25
2   Inspection  0.00

3 个答案:

答案 0 :(得分:1)

这样的事情怎么样?我在你定义的顺序(WO和OP)上构建了一个row_number,然后,我在每个WC上构建另一个row_number,按WO和OP排序。现在你有两个row_numbers。整个套装一个,每个WC一个。现在,当你从前者中减去后者时,只要有一行差异就会形成组,每次有一个MORe而不是一行,就会得到一个新的分组。不需要递归。

;with t (WO, OP, WC, Time) as
(
select 1,   10,  'Band Saw',    2.0
union all select 1,   15,  'Band Saw',    5.0
union all select 1,   17,  'Band Saw',    10.0
union all select 1,   20,  'CNC Lathe',   6.0
union all select 1,   22,  'Band Saw',    102.0
union all select 1,   30,  'Inspection',  33.0
union all select 2,   10,  'Band Saw',    1.5
union all select 2,   20,  'CNC Lathe',   6.00
union all select 2,   20,  'CNC Lathe',   2.00
union all select 2,   30,  'CNC Punch',   0.5
union all select 2,   40,  'Manual Ops',  1.25
union all select 2,   50,  'Inspection',  0.00
), rn as
(

    select 
        grp= row_number() over (order by WO, op) - row_number() over (partition by wo, wc order by wo, op),
        *
    from t
)
select grp, wo, wc, sum(time)
from rn
group by grp, wo, wc

编辑使用一个cte。还修复了二阶的分区。这比所提供的数据优于rcte,并且可能会更好地扩展,因为它不必递归任意次数。

答案 1 :(得分:0)

使用递归CTE:

;WITH
    cte1 AS
    (
        SELECT  WO, OP, WC, Time,
                ROW_NUMBER() OVER (ORDER BY WO, Op) AS RowNumber
        FROM    MyTable
    ),
    cte2 AS
    (
        SELECT  WO, OP, WC, Time, RowNumber,
                1 AS GroupID
        FROM    cte1
        WHERE   RowNumber = 1
        UNION ALL
        SELECT  cte1.WO, cte1.OP, cte1.WC, cte1.Time, cte1.RowNumber,
                CASE
                    WHEN cte1.WC = cte2.WC THEN cte2.GroupID
                    ELSE cte2.GroupID + 1
                END AS GroupID
        FROM    cte1
        INNER JOIN cte2 ON cte1.RowNumber = cte2.RowNumber + 1  
    )

SELECT  WO, WC, SUM(Time) As TotalTime
FROM    cte2
GROUP BY GroupID, WO, WC
OPTION  (MAXRECURSION 0)

我没有测试SQL Server 2005但它应该可以工作。如果您需要更多详细信息,请查询cte1cte2

答案 2 :(得分:0)

感谢Xedni,他为我提供了大部分答案。我不得不将Max(op)和排序添加到他提供的解决方案中。

;with t (WO, OP, WC, Time) as
    (
    select 1,   10,  'Band Saw',    2.0
    union all select 1,   15,  'Band Saw',    5.0
    union all select 1,   17,  'Band Saw',    10.0
    union all select 1,   20,  'CNC Lathe',   6.0
    union all select 1,   22,  'Band Saw',    102.0
    union all select 1,   30,  'Inspection',  33.0
    union all select 2,   10,  'Band Saw',    1.5
    union all select 2,   20,  'CNC Lathe',   6.00
    union all select 2,   20,  'CNC Lathe',   2.00
    union all select 2,   30,  'CNC Punch',   0.5
    union all select 2,   40,  'Manual Ops',  1.25
    union all select 2,   50,  'Inspection',  0.00
    ), rn as
    (

        select 
            grp= row_number() over (order by WO, op) - row_number() over (partition by wo, wc order by wo, op),
            *
        from t
    )
    select grp, wo, MAX(op) AS MaxOp, wc, sum(time)
    from rn
    group by grp, wo, wc
    ORDER BY wo, MaxOp