我有一张桌子,如下表
Domain Baseline PlanningPeriod Actual
-------------------------------------------------
Dom 1 Jan 18 1/1/18 10
Dom 1 Jan 18 1/2/18 20
Dom 1 Jan 18 1/3/18 25
Dom 1 Jan 18 1/4/18 24
Dom 1 Feb 18 1/2/18 60
Dom 1 Feb 18 1/3/18 20
Dom 1 Feb 18 1/5/18 40
Dom 1 Feb 18 1/12/18 70
Dom 1 Mar 18 1/3/18 11
Dom 1 Mar 18 1/4/18 12
Dom 1 Mar 18 1/12/18 18
Dom 1 Apr 18 1/4/18 40
Dom 1 Apr 18 1/5/18 25
Dom 1 Apr 18 1/6/18 15
-------------------------------------------------
请注意,域也不同
因此,我试图按域,基线,计划时间分组来获得额外的列交换性实际值。
为此,我做了以下查询
select domain,baseline,planningperiod, actual,sum(actual) over(partition
by domain, baseline order by domain,baseline,planningperiod) as cumilativeactual
幸运的是,它按预期工作,并给出了以下结果
Domain Baseline PlanningPeriod Actual CumActual
----------------------------------------------------------------
Dom 1 Jan 18 1/1/18 10 10
Dom 1 Jan 18 1/2/18 20 30
Dom 1 Jan 18 1/3/18 25 55
Dom 1 Jan 18 1/4/18 24 79
Dom 1 Feb 18 1/2/18 60 60
Dom 1 Feb 18 1/3/18 20 80
Dom 1 Feb 18 1/5/18 40 120
Dom 1 Feb 18 1/12/18 70 190
Dom 1 Mar 18 1/3/18 11 11
Dom 1 Mar 18 1/4/18 12 23
Dom 1 Mar 18 1/12/18 18 31
Dom 1 Apr 18 1/4/18 40 40
Dom 1 Apr 18 1/5/18 25 65
Dom 1 Apr 18 1/6/18 15 80
--------------------------------------------------------
但是我的要求有点疯狂。我需要每个组的最后一个元素作为下一组的第一个元素。但是组中的其他值与上面完全相同。所以我真的很困惑如何实现这一目标。我不喜欢使用游标,因为大约有2万条记录。
以上方法应如下工作。
Domain Baseline PlanningPeriod Actual CumActual
----------------------------------------------------------------
Dom 1 Jan 18 1/1/18 10 10
Dom 1 Jan 18 1/2/18 20 30
Dom 1 Jan 18 1/3/18 25 55
Dom 1 Jan 18 1/4/18 24 79
Dom 1 Feb 18 1/2/18 60 **79**
Dom 1 Feb 18 1/3/18 20 80
Dom 1 Feb 18 1/5/18 40 120
Dom 1 Feb 18 1/12/18 70 190
Dom 1 Mar 18 1/3/18 11 **190**
Dom 1 Mar 18 1/4/18 12 23
Dom 1 Mar 18 1/12/18 18 31
Dom 1 Apr 18 1/4/18 40 **31**
Dom 1 Apr 18 1/5/18 25 65
Dom 1 Apr 18 1/6/18 15 80
--------------------------------------------------------
答案 0 :(得分:5)
您可以将CTE和LAG()
用作
with cte as
(
select domain,
baseline,
planningperiod,
actual,
sum(actual) over(partition
by domain, baseline order by domain,baseline,planningperiod) as cumilativeactual
from t
)
select domain,
baseline,
planningperiod,
actual,
case when actual = cumilativeactual then
lag(cumilativeactual, 1, 0) over(order by domain,baseline,planningperiod)
else
cumilativeactual end as cumilativeactual
from cte
答案 1 :(得分:2)
您似乎希望使用一些其他逻辑来求和:
select domain, baseline, planningperiod, actual,
(case when seqnum = 1
then lag(periodtotal) over (partition by domain, baseline order by domain, baseline, planningperiod)
else cumulativeactual
end) as cum_actual
from (select domain, baseline, planningperiod, actual,
sum(actual) over (partition by domain, baseline order by domain, baseline, planningperiod) as cumulativeactual,
sum(actual) over (partition by domain, baseline) as periodtotal,
row_number() over (partition by domain, baseline order by domain, baseline, planningperiod) a seqnum
from t
) t;
答案 2 :(得分:2)
对于每个组,一些窗口功能可以帮助您将原始滚动总和替换为第一滚动总和。
示例数据(与示例相同的组和值):
IF OBJECT_ID('tempdb..#Amounts') IS NOT NULL
DROP TABLE #Amounts
CREATE TABLE #Amounts (
Code VARCHAR(10),
Actual INT,
Ordering INT IDENTITY)
INSERT INTO #Amounts (
Code,
Actual)
VALUES
('A', 10),
('A', 20),
('A', 25),
('A', 24),
('B', 60),
('B', 20),
('B', 40),
('B', 70),
('C', 11),
('C', 12),
('C', 18),
('D', 40),
('D', 25),
('D', 15)
查询:
;WITH WindowFunctions AS
(
SELECT
A.Code,
A.Actual,
DenseRank = DENSE_RANK() OVER (ORDER BY A.Code),
RowNumberByCodeDesc = ROW_NUMBER() OVER (PARTITION BY A.Code ORDER BY A.Ordering DESC),
RowNumberByCodeAsc = ROW_NUMBER() OVER (PARTITION BY A.Code ORDER BY A.Ordering ASC),
CumulativeGeneral = SUM(A.Actual) OVER (PARTITION BY A.Code ORDER BY A.Ordering ASC)
FROM
#Amounts AS A
)
SELECT
G.Code,
G.Actual,
G.DenseRank,
G.RowNumberByCodeAsc,
G.RowNumberByCodeDesc,
G.CumulativeGeneral,
PreviousFinishingCumulativeGeneral = P.CumulativeGeneral,
CorrectedCumulative = CASE
WHEN G.RowNumberByCodeAsc = 1 AND P.CumulativeGeneral IS NOT NULL THEN P.CumulativeGeneral
ELSE G.CumulativeGeneral END
FROM
WindowFunctions AS G
LEFT JOIN WindowFunctions AS P ON
G.DenseRank - 1 = P.DenseRank AND
P.RowNumberByCodeDesc = 1
结果:
Code Actual DenseRank RowNumberByCodeAsc RowNumberByCodeDesc CumulativeGeneral PreviousFinishingCumulativeGeneral CorrectedCumulative
A 10 1 1 4 10 NULL 10
A 20 1 2 3 30 NULL 30
A 25 1 3 2 55 NULL 55
A 24 1 4 1 79 NULL 79
B 60 2 1 4 60 79 79
B 20 2 2 3 80 79 80
B 40 2 3 2 120 79 120
B 70 2 4 1 190 79 190
C 11 3 1 3 11 190 190
C 12 3 2 2 23 190 23
C 18 3 3 1 41 190 41
D 40 4 1 3 40 41 41
D 25 4 2 2 65 41 65
D 15 4 3 1 80 41 80
答案 3 :(得分:0)
我猜因为输出是按cumilativeactual
排序的,因此您可以只使用case when first_value/min_value of group then (select max(CumActual) from prev_group (using row_number()-1)
答案 4 :(得分:0)
感谢@Sami提供了不错的解决方案。但是我对此进行了一些调整,我想它可能会使它更加准确。
我的查询是
with cte as
(
select domain,
baseline,
planningperiod,
actual,
sum(actual) over(partition
by domain, baseline order by domain,baseline,planningperiod) as cumilativeactual,DENSE_RANK() over(order by domain,baseline) as DRank
from t
)
select domain,
baseline,
planningperiod,
actual,
case when Drank> LAG(DRank,1,0) over(order by domain,baseline,planningperiod) then
lag(cumilativeactual, 1, 0) over(order by domain,baseline,planningperiod)
else
cumilativeactual end as cumilativeactual
from cte