如何获取已更新的列名称

时间:2016-06-26 14:04:46

标签: sql sql-server-2008 concat

假设我有一个这样的表:

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中的第一行表示帐户已打开,有人为帐户输入了一些详细信息,但其他人指示更改但我想知道哪些字段已更改。是否有任何建议或想法如何执行此操作?

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来测试更改。最后,您只需要按照自己的方式格式化字符串。