假设我有一个这样的表:
Table 1:
date account name type status open_account_date
31.12.14 1000 20 40 50 31.12.14
2.1.15 1000 10 10 50 31.12.14
3.1.15 1000 5 15 50 31.12.14
我希望在第一季度建立一个这样的汇总表:
account numOfChanges Changes
1000 4 (name, type)
表1中的第一行表示帐户已打开,有人为帐户输入了一些详细信息,但其他人指示更改但我想知道哪些字段已更改。是否有任何建议或想法如何执行此操作?
答案 0 :(得分:0)
DECLARE @StartOfQuarter DATE = '1/1/2015'
;WITH cteRcordStateBeforeQuarter AS (
SELECT
[date]
,account
,name
,[type]
,[status]
,open_account_date
,RowNum = ROW_NUMBER() OVER (PARTITION BY account ORDER BY [date] DESC)
FROM
#Table
WHERE
[date] < @StartOfQuarter
)
, cteRecordStatesDuringQuarter AS (
SELECT
[date]
,account
,name
,[type]
,[status]
,open_account_date
,RowNum = ROW_NUMBER() OVER (PARTITION BY account ORDER BY [date] ASC) + 1
--add 1 because the first row is going to be the last one prior to quarter
,LatestChangeRowNum = ROW_NUMBER() OVER (PARTITION BY account ORDER BY [date] DESC)
FROM
#Table
WHERE
DATEPART(QQ,[date]) = 1
--change to suite ongoing needs such as quater and YEAR([date]) = ??
)
, cteRecursive AS (
SELECT
[date]
,account
,name
,[type]
,[status]
,open_account_date
,RowNum
,LatestChangeRowNum = 0
,NumOfChanges = 0
,[Changes] = CAST('' AS VARCHAR(100))
FROM
cteRcordStateBeforeQuarter
WHERE
RowNum = 1
UNION ALL
SELECT
q.[date]
,q.account
,q.name
,q.[type]
,q.[status]
,q.open_account_date
,q.RowNum
,LatestChangeRowNum = CAST(q.LatestChangeRowNum AS INT)
,NumOfChanges = r.NumOfChanges
+ CASE WHEN ISNULL(q.name,-99999) <> ISNULL(r.name,-99999) THEN 1 ELSE 0 END
+ CASE WHEN ISNULL(q.[type],-99999) <> ISNULL(r.[type],-99999) THEN 1 ELSE 0 END
+ CASE WHEN ISNULL(q.[status],-99999) <> ISNULL(r.[status],-99999) THEN 1 ELSE 0 END
+ CASE WHEN ISNULL(q.open_account_date,'1/1/1900') <> ISNULL(r.open_account_date,'1/1/1900') THEN 1 ELSE 0 END
,[Changes] = CAST(ISNULL(r.[Changes],'')
+ CASE WHEN ISNULL(q.name,-99999) <> ISNULL(r.name,-99999) AND r.[Changes] NOT LIKE '%name%' THEN ',name' ELSE '' END
+ CASE WHEN ISNULL(q.[type],-99999) <> ISNULL(r.[type],-99999) AND r.[Changes] NOT LIKE '%type%' THEN ',type' ELSE '' END
+ CASE WHEN ISNULL(q.[status],-99999) <> ISNULL(r.[status],-99999) AND r.[Changes] NOT LIKE '%status%' THEN ',status' ELSE '' END
+ CASE WHEN ISNULL(q.open_account_date,'1/1/1900') <> ISNULL(r.open_account_date,'1/1/1900') AND r.[Changes] NOT LIKE '%open_account_date%' THEN ',open_account_date' ELSE '' END
AS VARCHAR(100))
FROM
cteRecordStatesDuringQuarter q
INNER JOIN cteRecursive r
ON q.account = r.account
AND q.RowNum = r.RowNum + 1
)
SELECT
account
,NumOfChanges
,[Changes] = REPLACE(IIF(CHARINDEX(',',[Changes]) = 1, RIGHT([Changes],LEN([Changes]) - 1),[Changes]),',',', ')
FROM
cteRecursive
WHERE
LatestChangeRowNum = 1
如果你在哪里使用SQL 2012 +它会更容易,因为你可以使用LAG或LEAD窗口函数和IIF而不是case。但是递归cte的效果也很好。我假设您的记录集将有多个帐户以及多个帐户,并且在该季度之前有多个记录状态。因此,您需要稍微调整日期逻辑,但这将为您提供要点。
首先找到季度之前的记录状态。然后查找本季度的所有变化。添加一些行号以确定哪个是第一个,哪个是最后一个更改。然后使用递归cte来测试更改。最后,您只需要按照自己的方式格式化字符串。