SQL Group By Column of Column Value not Fixed Value

时间:2014-02-21 16:55:50

标签: sql sql-server-2012

我有一个这样的数据表:

CommonURN GiftAidAmount GA_Status
14013084 2.00 45
14637494 20.00 45
14637496 1.00 45
14637508 5.00 45
14637520 10.00 45
14637525 19.00 45
14637562 10.00 45
14637586 12.00 45
14637590 3.00 45
14637649 5.00 45

我希望将行划分为总计1000英镑或更少的块,其中GA_Status值等于45。

到目前为止我所拥有的是:

CREATE TABLE #Temp
(CommonURN int,
GiftAidAmount money,
RunningSum money,
GroupID int);

WITH cte
(commonURN,giftAidAmount,running_sum)
AS
(SELECT
c.commonURN,
c.giftAidAmount,
        (select sum(c2.giftAidAmount)
        from dbo.[Campaign_Data] as c2 
        where 
            GA_Status = 45 and
            c2.commonURN <= c.commonURN)
FROM 
    [dbo].[Campaign_Data] c
WHERE GA_Status = 45)

INSERT INTO #Temp (CommonURN,GiftAidAmount,RunningSum,GroupID)
SELECT 
    commonURN,
    giftAidAmount, 
    running_sum,
    ceiling(running_sum/1000) as GroupID
FROM 
    cte 
ORDER BY
    commonURN

SELECT
    GroupID,
    COUNT(*) NumRows,
    SUM(GiftAidAmount) TotalGiftAid
FROM
    #Temp
GROUP BY GroupID

除了结果集中的一个组超过1000英镑外,这种方法效果很好:

GroupID NumRows TotalGiftAid
1   100 999.83
2   107 999.57
3   91  990.82
4   114 1009.34
5   114 995.40
6   58  455.65

我不明白为什么会这样。任何人都可以解释并帮助我解决它吗?或者建议一个更好的方法altogther?

2 个答案:

答案 0 :(得分:1)

您可以使用变量获取单表更新的运行值,并在运行值超过1000时调整变量以重置。您还可以基于此更新GroupID。我就是这样做的。我在5到30之间的任何地方插入一堆随机数量。金额越大,您越有可能遇到运行值远低于1000的情况,但下一个值会使运行值超过1000:

-- insert test data
declare @Campaign_Data table
    (
    GiftAidAmount money,
    RunningValue money,
    GroupID int
    )
while (select count(*) from @Campaign_Data) < 2000
    begin
        insert into @Campaign_Data (GiftAidAmount)
            values (round(rand()*25,2)+5)
    end

-- update Running Value and GroupID; restart when amount exceeds 1000
declare @RunningValue money,
        @GroupID int        
set @RunningValue = 0
set @GroupID = 1
update @Campaign_Data
    set 
        @GroupID = GroupID = case when @RunningValue + GiftAidAmount > 1000
                                  then @GroupID + 1
                                  else @GroupID
                             end,
        @RunningValue = RunningValue = case when @RunningValue + GiftAidAmount > 1000
                                            then GiftAidAmount
                                            else @RunningValue + GiftAidAmount
                                       end

-- return values grouped by GroupID
select
    GroupID,
    count(GroupID) NumRows,
    sum(GiftAidAmount) TotalGiftAid
from @Campaign_Data
group by
    GroupID
order by
    GroupID

答案 1 :(得分:0)

试试这个:

SELECT
    GroupID,
    COUNT(*) NumRows,
    SUM(GiftAidAmount) TotalGiftAid
FROM
    #Temp
GROUP BY GroupID
HAVING SUM(GiftAidAmount) < 1000