我有一个看起来像这样的表:
create function dbo.fn(@cYear numeric, @rate float)
returns float
as
begin
declare @pYear numeric
declare @return float
set @pYear = @cYear - 1
set @return = (select
case
when Value < 0 and @rate > 0 then null
when Value < 0 then Value + @rate
else @rate
end
from Table1
where [year] = @pYear)
return @return
end
我需要执行一个导致新列的条件聚合。条件如下:
如果值为负,则聚合开始并且在值为正之前不会停止。然后没有什么,直到值再次为负...结果将如下所示:
{{1}}
这个udf和我一样接近:
{{1}}
我对c#中的答案没问题,如果这会更容易但更喜欢SQL。我所做的功能的问题是我需要能够从上一行中获取结果,以便在值为正时添加值。
我整夜都在这里寻找线索,没有快乐......
编辑:因此,将这些视为您的运营商应用于您的手机账单的年度CPI值...他们只会增加您的账单CPI,而不会减少它(如果CPI为负) ......但如果当年的CPI为正(或总和为正),它们将抵消前几年的CPI负值当前年度CPI ...
这可能会有所帮助,也可能没有帮助,但情况就是这样。
答案 0 :(得分:6)
DECLARE @t TABLE ( [Year] INT, Value MONEY )
INSERT INTO @t
VALUES ( 2013, -0.0016 ),
( 2014, -0.0001 ),
( 2015, 0.0025 ),
( 2016, -0.0003 ),
( 2017, 0.0023 ),
( 2018, 0.0002 )
SELECT t1.Year ,
t1.Value ,
oa.AggCol
FROM @t t1
OUTER APPLY ( SELECT SUM(Value) AS AggCol
FROM @t t2
WHERE Year <= t1.Year
AND Year > ( SELECT ISNULL(MAX(Year), 0)
FROM @t
WHERE Year < t1.Year AND Value > 0)
) oa
输出:
Year Value AggCol
2013 -0.0016 -0.0016
2014 -0.0001 -0.0017
2015 0.0025 0.0008
2016 -0.0003 -0.0003
2017 0.0023 0.002
2018 0.0002 0.0002
这意味着:对于每一行,给我一个小于或等于当前行的值的总和,并且大于在当前行之前出现的具有正值的最大行,或者如果没有找到这样的值则从0开始。
答案 1 :(得分:0)
您也可以使用窗口功能来执行此操作:
;WITH PrevValues AS (
SELECT Year, Value,
LAG(Value) OVER (ORDER BY Year) AS prevValue
FROM Table1
), Flags AS (
SELECT Year, Value,
CASE
WHEN Value < 0 AND prevValue > 0 THEN 2 -- next slice
WHEN Value < 0 OR prevValue < 0 THEN 1 -- same slice
WHEN Value > 0 AND prevValue > 0 THEN -1 -- not in a slice
END AS flag
FROM PrevValues
), Islands AS (
SELECT Year, Value,
CASE
WHEN flag = -1 THEN -1
ELSE SUM(flag) OVER (ORDER BY Year)
-
ROW_NUMBER() OVER (ORDER BY Year)
END AS grp
FROM Flags
)
SELECT Year, Value,
CASE
WHEN grp = -1 THEN Value
ELSE SUM(Value) OVER (PARTITION BY grp ORDER BY Year)
END AS AggCol
FROM Islands
ORDER BY Year
这个想法是识别应用运行总和的行的岛。
答案 2 :(得分:0)
DECLARE @t TABLE ( [Year] INT, Value MONEY )
INSERT INTO @t
VALUES (2013,-0.0016),(2014,0.0001),(2015,0.0025),(2016,-0.0003),(2017,0.0023),(2018,0.0002)
;WITH cteRowNum AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY Year) as RowNum
FROM
@t
)
, cteRecursive AS (
SELECT
Year
,Value
,Value as AggCol
,RowNum
FROM
cteRowNum
WHERe
RowNum = 1
UNION ALL
SELECT
c.Year
,c.Value
,CASE
WHEN AggCol >= 0 THEN c.Value
ELSE AggCol + c.Value
END
,c.RowNum
FROM
cteRecursive r
INNER JOIN cteRowNum c
ON r.RowNum + 1 = c.RowNum
)
SELECT Year, Value, AggCol
FROM
cteRecursive
注意这是一个不同的数据设置,而不是你提供的数据!这是结果
Year Value AggCol
2013 -0.0016 -0.0016
2014 0.0001 -0.0015
2015 0.0025 0.001
2016 -0.0003 -0.0003
2017 0.0023 0.002
2018 0.0002 0.0002
原始测试数据存在的问题是,它没有考虑到需要多个顺序正记录才能使运行总和为正的情况。 随后我发布答案的其他答案都是错误的。所以我只将2014年的记录改为正.0001,你可以看到这个解决方案是如何工作的,而其他人则没有。
使用窗口函数可能有这样做的方法,但递归cte非常简单,所以我走了那条路:
这是Giorgos&amp; Sons的结果。如果您对测试数据进行更改,Giorgi会给出答案:
Year Value AggCol
2013 -0.0016 -0.0016
2014 0.0001 -0.0015
2015 0.0025 0.0025
2016 -0.0003 -0.0003
2017 0.0023 0.002
2018 0.0002 0.0002
您可以看到2015年AggCol的问题是错误的
请注意我认为答案是很好的尝试,并且在缺口/岛屿方面展示了一些真正的技能/代码。我不是试图攻击只是提高帖子的质量。