我的总价值包含用户付款,因为他注册了。 自注册之日起的每年,用户必须支付高级会员资格,但不必在同一年支付。用户可以付e。例如。回来三年。或者提前几年接下来的三年。
多年的费率如下:
year | rate
2014 | 100
2015 | 100
2016 | 50
2017 | 150
2018 | 100
这是用户应该支付的价值。但他可以转移所需的更少或更多的钱。假设用户支付了438美元。他什么时候这样做并不重要。可能是2014年或本年度。我们只想知道他是否已经支付了他应该支付的所有费用,这是从2014年到当年的费用。
我想要做的是将他应支付的每年的转账总额(计算并存储在一个变量中)除以检查他是否支付了所有款项或是否有超额付款/少付款。
结果我想得到:
year | rate | payed
2014 | 100 | 100
2015 | 100 | 100
2016 | 50 | 50
2017 | 150 | 150
2018 | 100 | 38
因此,用户已经支付了他应该更新的所有费用,并且还有38美元的超额付款。
使用循环/光标我可以这样做,但不能想到要使用的窗口函数。任何提示?无法找到如何在这种情况下查询谷歌。
示例(解决方案正在运行但寻找等效的窗口函数)
DECLARE @total DECIMAL = 438
;WITH data AS
(
SELECT *, @total - (SELECT SUM(tt.rate) FROM
(VALUES
(2013, 100),
(2014, 100),
(2015, 100),
(2016, 100),
(2017, 100),
(2018, 100)) tt([Year], Rate)
WHERE tt.[Year] < t.[Year]) AS Payed
FROM (VALUES
(2013, 100),
(2014, 100),
(2015, 100),
(2016, 100),
(2017, 100),
(2018, 100)) t([Year], Rate)
),
prepared AS
(
SELECT d.[Year], @total AS Total, d.Rate,
CASE
WHEN ISNULL(d.Payed, d.Rate) <= 0 THEN NULL
WHEN @total < d.Rate THEN @total ELSE ISNULL(d.Payed, d.Rate)
END AS Payed
FROM data d
)
SELECT p.[Year], @total AS Total, p.Rate,
CASE
WHEN p.Payed >= p.Rate THEN p.Rate
ELSE p.Payed
END Payed
FROM prepared p
答案 0 :(得分:1)
如果您使用的是SQL Server 2012+,则使用SUM() OVER (ORDER BY...)
计算未结(或多付)的总金额非常容易。
示例数据
DECLARE @TotalPaid money = 438;
DECLARE @Rates TABLE (Y int, Rate money);
INSERT INTO @Rates (Y, Rate) VALUES
(2014, 100),
(2015, 100),
(2016, 50),
(2017, 150),
(2018, 100),
(2019, 100);
<强>查询强>
WITH
CTE
AS
(
SELECT
Y
,Rate
,SUM(Rate) OVER (ORDER BY Y
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS SumRate
FROM @Rates
)
,CTE2
AS
(
SELECT
Y
,Rate
,SumRate
,@TotalPaid - SumRate AS PaidExtra
FROM CTE
)
SELECT
Y
,Rate
,SumRate
,PaidExtra
,CASE WHEN PaidExtra >= 0
THEN Rate
ELSE Rate + PaidExtra
END AS Paid
FROM CTE2
ORDER BY Y
;
<强>结果强>
+------+--------+---------+-----------+--------+
| Y | Rate | SumRate | PaidExtra | Paid |
+------+--------+---------+-----------+--------+
| 2014 | 100.00 | 100.00 | 338.00 | 100.00 |
| 2015 | 100.00 | 200.00 | 238.00 | 100.00 |
| 2016 | 50.00 | 250.00 | 188.00 | 50.00 |
| 2017 | 150.00 | 400.00 | 38.00 | 150.00 |
| 2018 | 100.00 | 500.00 | -62.00 | 38.00 |
| 2019 | 100.00 | 600.00 | -162.00 | -62.00 |
+------+--------+---------+-----------+--------+
答案 1 :(得分:0)
我不确定我是100%,但可能是这样:
工作示例:http://rextester.com/OCHHR61883
DECLARE @total DECIMAL = 438
;WITH data AS
(
SELECT *, @total - (SELECT SUM(tt.rate) FROM
(VALUES
(2013, 100),
(2014, 100),
(2015, 100),
(2016, 100),
(2017, 100),
(2018, 100)) tt([Year], Rate)
WHERE tt.[Year] < t.[Year]) AS Payed
FROM (VALUES
(2013, 100),
(2014, 100),
(2015, 100),
(2016, 100),
(2017, 100),
(2018, 100)) t([Year], Rate)
),
prepared AS
(
SELECT d.[Year], @total AS Total, d.Rate
, case when @total-sum(rate) over( Order by year asc)<0 then 0
else @total-sum(rate) over( Order by year asc) end as RunningTotal
FROM data d
)
Select * from prepared
这给了我们:
+----+------+-------+------+--------------+
| | Year | Total | Rate | RunningTotal |
+----+------+-------+------+--------------+
| 1 | 2013 | 438 | 100 | 338 |
| 2 | 2014 | 438 | 100 | 238 |
| 3 | 2015 | 438 | 100 | 138 |
| 4 | 2016 | 438 | 100 | 38 |
| 5 | 2017 | 438 | 100 | 0 |
| 6 | 2018 | 438 | 100 | 0 |
+----+------+-------+------+--------------+
或者现在我或许更接近这个:
DECLARE @total DECIMAL = 438
;WITH data AS
(
SELECT *, @total - (SELECT SUM(tt.rate) FROM
(VALUES
(2013, 100),
(2014, 100),
(2015, 100),
(2016, 100),
(2017, 100),
(2018, 100)) tt([Year], Rate)
WHERE tt.[Year] < t.[Year]) AS Payed
FROM (VALUES
(2013, 100),
(2014, 100),
(2015, 100),
(2016, 100),
(2017, 100),
(2018, 100)) t([Year], Rate)
),
prepared AS
(
SELECT d.[Year], @total AS Total, d.Rate
, case when @total-sum(rate) over( Order by year asc) > 0 then d.rate
when @total-sum(rate) over( Order by year asc) < 0 and sum(rate) over( Order by year asc) > 0 and d.rate+@total-sum(rate) over( Order by year asc) < 0 then 0
when @total-sum(rate) over( Order by year asc) < 0 and sum(rate) over( Order by year asc) > 0 then d.rate+@total-sum(rate) over( Order by year asc)
end as Paid
FROM data d
)
Select * from prepared
+----+------+-------+------+------+
| | Year | Total | Rate | Paid |
+----+------+-------+------+------+
| 1 | 2013 | 438 | 100 | 100 |
| 2 | 2014 | 438 | 100 | 100 |
| 3 | 2015 | 438 | 100 | 100 |
| 4 | 2016 | 438 | 100 | 100 |
| 5 | 2017 | 438 | 100 | 38 |
| 6 | 2018 | 438 | 100 | 0 |
+----+------+-------+------+------+
或基于第一个查询的不同方法: http://rextester.com/BVSDS50299
DECLARE @total DECIMAL = 438
;WITH data AS
(
SELECT *, @total - (SELECT SUM(tt.rate) FROM
(VALUES
(2013, 100),
(2014, 100),
(2015, 100),
(2016, 100),
(2017, 100),
(2018, 100)) tt([Year], Rate)
WHERE tt.[Year] < t.[Year]) AS Payed
FROM (VALUES
(2013, 100),
(2014, 100),
(2015, 100),
(2016, 100),
(2017, 100),
(2018, 100)) t([Year], Rate)
),
prepared AS
(
SELECT d.[Year], @total AS Total, d.Rate
, case when @total-sum(rate) over( Order by year asc) < 0 then 0
else case when @total-sum(rate) over( Order by year asc)> d.rate then d.rate else @total-sum(rate) over( Order by year asc) end end
as RunningTotal
FROM data d
)
Select * from prepared
给出了与第二个查询相同的结果。