希望这不是另一个问题的愚蠢,但我无法在其他任何地方看到它 - 这也是another question I asked的简化版本,希望能让我开始研究如何处理它。
我希望在每个月至少付款一次的情况下计算出连续的付款范围。
我有以下示例数据
CREATE TABLE #data
(
Contact_reference NVARCHAR(55)
,Date_payment DATETIME
,Payment_value MONEY
)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2003-06-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2004-06-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2004-12-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-04-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-05-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-06-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-07-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-08-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-09-08',12.82)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-10-10',12.8205)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-11-10',12.8205)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2005-12-10',12.8205)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2006-01-10',12.8205)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2006-02-10',12.8205)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2006-02-28',12.8205)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2006-04-12',12.8205)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2006-05-10',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2007-06-11',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2007-07-10',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2007-08-09',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2007-09-10',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2007-10-09',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2007-11-09',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2007-12-10',19.2308)
INSERT INTO #data VALUES ('18EC3CD2-3065-4FF4-BE40-000004228590','2008-01-10',19.2308)
我希望能够做的是为每个联系人计算他们连续给出的范围(定义为每个日历月至少给出一次),连续付款的数量,每个总价值范围(理想情况下,如果可能的话,当前范围与最近范围结束之间的差距)。
对于上面的测试数据,我的输出将如下所示:
CREATE TABLE #results
(
contact_reference NVARCHAR(55)
,Range_start DATETIME
,Range_end DATETIME
,Payments INT
,Value MONEY
,months_until_next_payment INT --works out the gap between the range_end date for a group and the range_start date for the next group
)
INSERT INTO #results VALUES('18EC3CD2-3065-4FF4-BE40-000004228590','2003-06-08','2003-06-08',1,12.82,12)
INSERT INTO #results VALUES('18EC3CD2-3065-4FF4-BE40-000004228590','2004-06-08','2004-06-08',1,12.82,6)
INSERT INTO #results VALUES('18EC3CD2-3065-4FF4-BE40-000004228590','2004-12-08','2004-12-08',1,12.82,4)
INSERT INTO #results VALUES('18EC3CD2-3065-4FF4-BE40-000004228590','2005-04-08','2006-02-28',12,153.843,2)
INSERT INTO #results VALUES('18EC3CD2-3065-4FF4-BE40-000004228590','2006-04-12','2008-06-06',27,416.6673,NULL)
我使用岛屿或迭代寻找答案,但我坦率地说甚至不知道从哪里开始将它们应用到我的问题中,所以任何帮助都会受到大力赞赏:)
答案 0 :(得分:4)
修改:我已添加到months_until_next_payment
列中。这可以在应用程序中更有效地完成,而不是使用自联接,但是因为SQL Server没有任何特别令人满意的方式来引用下一行和前一行。
;WITH base AS (
SELECT Contact_reference ,
Payment_value,
DATEPART(YEAR, Date_payment)*12 + DATEPART(MONTH, Date_payment) -
DENSE_RANK() OVER
(PARTITION BY Contact_reference
ORDER BY DATEPART(YEAR, Date_payment)*12 + DATEPART(MONTH, Date_payment)) AS G,
Date_payment
FROM #data
),
cte AS
(
SELECT
Contact_reference,
ROW_NUMBER() over (partition by Contact_reference
order by MIN(Date_payment)) RN,
MIN(Date_payment) Range_start,
MAX(Date_payment) Range_end,
COUNT(Payment_value) Payments,
SUM(Payment_value) Value
FROM base
GROUP BY Contact_reference, G
)
SELECT
c1.Contact_reference,
c1.Payments,
c1.Range_end,
c1.Range_start,
c1.Value,
DATEDIFF(month, c1.Range_end,c2.Range_start) months_until_next_payment
FROM cte c1
LEFT join cte c2 ON c1.Contact_reference=c2.Contact_reference and c2.RN = c1.RN+1
答案 1 :(得分:1)
您可以使用光标来完成。像c#/ java这样的语言是解决这个问题的更好选择。
DECLARE @date DATETIME
DECLARE @nextDate DATETIME
DECLARE @rangeStart DATETIME
DECLARE @rangeEnd DATETIME
DECLARE @value decimal(18,2)
DECLARE @valueSum decimal(18,2)
DECLARE @count int
DECLARE @PaymentCursor CURSOR
SET @PaymentCursor = CURSOR FOR
SELECT Date_payment, Payment_value FROM #data
ORDER BY Date_payment
OPEN @PaymentCursor
FETCH NEXT FROM @PaymentCursor INTO @nextDate, @value
SET @date = @nextDate
SET @rangeStart = @nextDate
SET @valueSum = 0
SET @count = 0
WHILE (@@FETCH_STATUS = 0)
BEGIN
FETCH NEXT FROM @PaymentCursor INTO @nextDate, @value
SET @count = @count + 1
SET @valueSum = @valueSum + @value
IF (DATEDIFF(mm, @date, @nextDate) > 1)
BEGIN
SELECT @rangeStart AS RangeStart, @date AS RangeEnd, @count AS Coount, @valueSum AS VALUE, DATEDIFF(mm, @date, @nextDate) AS months_until_next_payment
SET @valueSum = 0
SET @count = 0
SET @rangeStart = @nextDate
END
SET @date = @nextDate
END
SELECT @rangeStart AS RangeStart, @date AS RangeEnd, @count AS Coount, @valueSum AS VALUE, null AS months_until_next_payment
CLOSE @PaymentCursor
DEALLOCATE @PaymentCursor