动态选择已更改的列名

时间:2015-12-18 15:21:10

标签: sql tsql sql-server-2008-r2

我有一张桌子如下所示。

ID NAME ADDRESS CITY ROLE Date_Modified

1 Tom某事奥斯汀经理X

2汤姆没有奥斯汀校长Y

3汤姆任何dallas VP Z

如何编写查询以选择在条目1,2和3之间更改的列名?目前,我正在构建一份需要识别变更的报告。这是我到目前为止所需要的,并且需要使用它。

我需要能够通过存储过程检测并查看下面的输出。

Id ColumnName DateChanged

2地址Y

2角色Y

3地址Z

3角色Z

1 个答案:

答案 0 :(得分:1)

如果我正确理解了您的问题,您需要检测从一行到另一行的更改并取消数据的转换。 LAG的使用需要SQL Server 2012或更高版本。

;with cte as (
    -- LAG for id is used to skip first row from selection
    select id, LAG(id, 1) OVER (ORDER BY id) AS OldId, 
        address, LAG(address, 1) OVER (ORDER BY id) AS OldAddress, 
        role, LAG(role, 1) OVER (ORDER BY id) AS OldRole,
        Date_Modified
    from audit_data
)
SELECT id, ColName, data_col, Date_Modified
FROM
(
    select id, address, role, Date_Modified
    from cte
    -- detect any change in monitored data
    where ((OldAddress IS NULL OR address <> OldAddress)
        OR (OldRole IS NULL OR role <> OldRole))
        AND OldId IS NOT NULL
) AS cp
-- unpivot address and role into data_col column
UNPIVOT 
(
  data_col FOR ColName IN (address, role)
) AS up;

用于设置的数据:

-- drop table audit_data
create table audit_data (
    id int,
    name VARCHAR(100),
    address VARCHAR(100),
    city varchar(100),
    role VARCHAR(100),
    Date_Modified DATETIME2
)



insert into audit_data values (1, 'Tom', 'something', 'austin', 'manager', '20150103'),
    (2, 'Tom', 'nothing', 'austin', 'principa', '20150205'),
    (3, 'Tom', 'anything', 'dallas', 'VP', '20150314')
go

[编辑] SQL 2008R2版本:

;with ad_cte as (
    select id, address, role, Date_Modified, ROW_NUMBER() OVER (ORDER BY id) RowNo
    from audit_data
),
cte as (
    select ad.id,
        ad.address, ad_old.address AS OldAddress, 
        ad.role, ad_old.role AS OldRole,
        ad.Date_Modified
    from ad_cte ad
        join ad_cte ad_old on ad_old.RowNo + 1 = ad.RowNo
)
SELECT id, ColName, data_col, Date_Modified
FROM
(
    select id, address, role, Date_Modified
    from cte
    -- detect any change in monitored data
    where ((OldAddress IS NULL OR address <> OldAddress)
        OR (OldRole IS NULL OR role <> OldRole))
        -- this should be changed for generality
        AND cte.id > 1
) AS cp
-- unpivot address and role into data_col column
UNPIVOT 
(
  data_col FOR ColName IN (address, role)
) AS up;