我目前正在尝试根据未结余额,剩余付款数量和这些付款的价值创建一种预测类型。我有一个数据结构如下
AccountNo|Balance |Payments |Frequency|PaymentsRemaining
12584 |1100 |100 |MX |11
12887 |23656 |500 |MX |47
13190 |2000 |22 |WK |90
余额是欠款,付款是每月/每周付款,频率是每月或每周,剩余剩余。
我想要完成的是计算未来19年每年将收集多少作为一个单独的专栏。像这样 -
AccountNo|Balance |Payments|Frequency|PaymentsRemaining|2014 |2015 |2016 |2017
12584 |1100 |100 |MX |11 |1100 |0 |0 |0
12887 |23656 |500 |MX |47 |568 |568 |568 |568
13190 |2000 |22 |WK |90 |1144 |856 | |
*数据只是一个例子,并且是手工制作的
我甚至不确定从哪里开始尝试在SQL中复制它,因为我从来没有必要创建类似于此的任何内容。我希望我已经提供了足够的数据,并希望有人可以帮助我,即使它指向我追求自己的方向。
答案 0 :(得分:1)
2016年最后一行的值6212似乎不对,其余动态PIVOT
可以解决此问题。
基本思路是以列
生成未来付款WITH N(N) AS (
SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7
UNION ALL SELECT 8 UNION ALL SELECT 9
), Y AS (
SELECT _Year = YEAR(SYSDATETIME()) + u.N + t.N * 10
, ID = u.N + t.N * 10
FROM N u
CROSS JOIN N t
WHERE u.N + t.N * 10 < 20
), H (freq, times) AS (
SELECT 'WK', 52 UNION ALL SELECT 'MX', 12
)
SELECT AccountNo, Balance, Payments, Frequency, PaymentsRemaining
, _Year
, yearPayment = Payments
* ((PaymentsRemaining - H.times * ID + H.times) / 2
- ABS(PaymentsRemaining - H.times * ID - H.times) / 2)
FROM Data d
INNER JOIN H ON d.Frequency = H.freq
CROSS JOIN Y
WHERE PaymentsRemaining - H.times * ID > 0
ORDER BY AccountNo, _Year
以N
和Y
生成未来年份
H
作为帮助表,存储支付数量将在一年内为频率类型进行(我希望这些是静态的)。
((PaymentsRemaining - H.times * ID + H.times) / 2 - ABS(PaymentsRemaining - H.times * ID - H.times) / 2)
使用公式PaymentsRemaining - H.times * ID
计算H.times
和(A + B) / 2 - ABS(A - B) / 2
之间的最小值
然后使用PIVOT
将列转换为行,下面是具有有限年数的测试查询
WITH N(N) AS (
SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7
UNION ALL SELECT 8 UNION ALL SELECT 9
), Y AS (
SELECT _Year = YEAR(SYSDATETIME()) + u.N + t.N * 10
, ID = u.N + t.N * 10
FROM N u
CROSS JOIN N t
WHERE u.N + t.N * 10 < 20
), H (freq, times) AS (
SELECT 'WK', 52 UNION ALL SELECT 'MX', 12
)
SELECT AccountNo, Balance, Payments, Frequency, PaymentsRemaining
, [2014], [2015], [2016], [2017]
FROM (SELECT AccountNo, Balance, Payments, Frequency, PaymentsRemaining
, _Year
, yearPayment = Payments
* ((PaymentsRemaining - H.times * ID + H.times) / 2
- ABS(PaymentsRemaining - H.times * ID - H.times) / 2)
FROM Data d
INNER JOIN H ON d.Frequency = H.freq
CROSS JOIN Y
WHERE PaymentsRemaining - H.times * ID > 0) D
PIVOT
(MAX(yearPayment) FOR _Year IN ([2014], [2015], [2016], [2017])) pvt
可以动态
DECLARE @query AS NVARCHAR(MAX)
DECLARE @cols AS NVARCHAR(MAX)
WITH N(N) AS (
SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7
UNION ALL SELECT 8 UNION ALL SELECT 9
), Y AS (
SELECT _Year = YEAR(SYSDATETIME()) + u.N + t.N * 10
FROM N u
CROSS JOIN N t
WHERE u.N + t.N * 10 < 20
)
SELECT @cols = STUFF((SELECT ',' + QUOTENAME([_Year])
FROM Y
ORDER BY _Year
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '')
SELECT @query ='
WITH N(N) AS (
SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7
UNION ALL SELECT 8 UNION ALL SELECT 9
), Y AS (
SELECT _Year = YEAR(SYSDATETIME()) + u.N + t.N * 10
, ID = u.N + t.N * 10
FROM N u
CROSS JOIN N t
WHERE u.N + t.N * 10 < 20
), H (freq, times) AS (
SELECT ''WK'', 52 UNION ALL SELECT ''MX'', 12
)
SELECT AccountNo, Balance, Payments, Frequency, PaymentsRemaining
, ' + @cols + '
FROM (SELECT AccountNo, Balance, Payments, Frequency, PaymentsRemaining
, _Year
, yearPayment = Payments
* ((PaymentsRemaining - H.times * ID + H.times) / 2
- ABS(PaymentsRemaining - H.times * ID - H.times) / 2)
FROM Data d
INNER JOIN H ON d.Frequency = H.freq
CROSS JOIN Y
WHERE PaymentsRemaining - H.times * ID > 0) D
PIVOT
(MAX(yearPayment) FOR _Year IN (' + @cols + ')) pvt'
execute(@query);
如果在第一年开始到付款开始之间存在延迟,则可以使用CTE
H
的相同形式将信息存储在其他CTE
中例如,滞后六个月的值将是26周和6个月,这些值将被添加到年底留下的付款,因此剩余付款的公式将从
PaymentsRemaining - H.times * ID
到
PaymentsRemaining - H.times * ID + L.times
基础查询,用了几年,变成了
WITH N(N) AS (
SELECT N FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) D(N)
), Y AS (
SELECT _Year = YEAR(SYSDATETIME()) + u.N + t.N * 10
, ID = u.N + t.N * 10
FROM N u
CROSS JOIN N t
WHERE u.N + t.N * 10 < 20
), H (freq, times) AS (
SELECT 'WK', 52 UNION ALL SELECT 'MX', 12
), L (freq, times) AS (
SELECT 'WK', 26 UNION ALL SELECT 'MX', 6
)
SELECT AccountNo, Balance, Payments, Frequency, PaymentsRemaining
, [2014], [2015], [2016], [2017], [2018]
FROM (SELECT AccountNo, Balance, Payments, Frequency, PaymentsRemaining
, _Year
, yearPayment = Payments
* (((PaymentsRemaining - H.times * ID + L.times + H.times) / 2
- ABS(PaymentsRemaining - H.times * ID + L.times - H.times) / 2)
- CASE WHEN _Year = Year(SYSDATETIME()) THEN L.Times
ELSE 0
END)
FROM Data d
INNER JOIN H ON d.Frequency = H.freq
INNER JOIN L ON d.Frequency = L.freq
CROSS JOIN Y
WHERE PaymentsRemaining - H.times * ID + L.times > 0) D
PIVOT
(MAX(yearPayment) FOR _Year IN ([2014], [2015], [2016], [2017])) pvt
动态表单是
DECLARE @query AS NVARCHAR(MAX)
DECLARE @cols AS NVARCHAR(MAX)
WITH N(N) AS (
SELECT N FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) D(N)
), Y AS (
SELECT _Year = YEAR(SYSDATETIME()) + u.N + t.N * 10
FROM N u
CROSS JOIN N t
WHERE u.N + t.N * 10 < 20
)
SELECT @cols = STUFF((SELECT ',' + QUOTENAME([_Year])
FROM Y
ORDER BY _Year
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '')
SELECT @query ='
WITH N(N) AS (
SELECT N FROM (VALUES (0), (1), (2), (3), (4)
, (5), (6), (7), (8), (9)) D(N)
), Y AS (
SELECT _Year = YEAR(SYSDATETIME()) + u.N + t.N * 10
, ID = u.N + t.N * 10
FROM N u
CROSS JOIN N t
WHERE u.N + t.N * 10 < 20
), H (freq, times) AS (
SELECT ''WK'', 52 UNION ALL SELECT ''MX'', 12
), L (freq, times) AS (
SELECT ''WK'', 26 UNION ALL SELECT ''MX'', 6
)
SELECT AccountNo, Balance, Payments, Frequency, PaymentsRemaining
, ' + @cols + '
FROM (SELECT AccountNo, Balance, Payments, Frequency, PaymentsRemaining
, _Year
, yearPayment = Payments
* (((PaymentsRemaining - H.times * ID + L.times + H.times) / 2
- ABS(PaymentsRemaining - H.times * ID + L.times - H.times) / 2)
- CASE WHEN _Year = Year(SYSDATETIME()) THEN L.Times
ELSE 0
END)
FROM Data d
INNER JOIN H ON d.Frequency = H.freq
INNER JOIN L ON d.Frequency = L.freq
CROSS JOIN Y
WHERE PaymentsRemaining - H.times * ID + L.times > 0) D
PIVOT
(MAX(yearPayment) FOR _Year IN (' + @cols + ')) pvt'
execute(@query);